summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2007-08-15 13:38:23 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2007-08-15 13:38:23 +0000
commita4c84de53c3855b52955df5633e2b1a4347667f8 (patch)
tree760d1a67e3c35154e987ecd171696b2b7a4c942d
parenta8fc5f180de26ddfbc94687739fbad84a66b711c (diff)
changes specific to GTK-OSX build
git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@2303 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--SConstruct9
-rw-r--r--gtk2_ardour/SConscript72
-rw-r--r--gtk2_ardour/ardour_ui.h2
-rw-r--r--gtk2_ardour/ardour_ui_ed.cc15
-rw-r--r--gtk2_ardour/sync-menu.c795
-rw-r--r--gtk2_ardour/sync-menu.h27
6 files changed, 887 insertions, 33 deletions
diff --git a/SConstruct b/SConstruct
index b3cada1303..1844969b89 100644
--- a/SConstruct
+++ b/SConstruct
@@ -29,6 +29,7 @@ opts.AddOptions(
('ARCH', 'Set architecture-specific compilation flags by hand (all flags as 1 argument)',''),
BoolOption('AUDIOUNITS', 'Compile with Apple\'s AudioUnit library. (experimental)', 0),
BoolOption('COREAUDIO', 'Compile with Apple\'s CoreAudio library', 0),
+ BoolOption('GTKOSX', 'Compile for use with GTK-OSX, not GTK-X11', 0),
BoolOption('DEBUG', 'Set to build with debugging information and no optimizations', 0),
PathOption('DESTDIR', 'Set the intermediate install "prefix"', '/'),
EnumOption('DIST_TARGET', 'Build target for cross compiling packagers', 'auto', allowed_values=('auto', 'i386', 'i686', 'x86_64', 'powerpc', 'tiger', 'panther', 'none' ), ignorecase=2),
@@ -816,7 +817,13 @@ if conf.CheckCHeader('alsa/asoundlib.h'):
subst_dict['%MIDITYPE%'] = "alsa/sequencer"
elif conf.CheckCHeader('/System/Library/Frameworks/CoreMIDI.framework/Headers/CoreMIDI.h'):
# this line is needed because scons can't handle -framework in ParseConfig() yet.
- libraries['sysmidi'] = LibraryInfo (LINKFLAGS= '-framework CoreMIDI -framework CoreFoundation -framework CoreAudio -framework CoreServices -framework AudioUnit -framework AudioToolbox -bind_at_load')
+ if env['GTKOSX']:
+ # We need Carbon as well as the rest
+ libraries['sysmidi'] = LibraryInfo (
+ LINKFLAGS = ' -framework CoreMIDI -framework CoreFoundation -framework CoreAudio -framework CoreServices -framework AudioUnit -framework AudioToolbox -framework Carbon -bind_at_load' )
+ else:
+ libraries['sysmidi'] = LibraryInfo (
+ LINKFLAGS = ' -framework CoreMIDI -framework CoreFoundation -framework CoreAudio -framework CoreServices -framework AudioUnit -framework AudioToolbox -bind_at_load' )
env['SYSMIDI'] = 'CoreMIDI'
subst_dict['%MIDITAG%'] = "ardour"
subst_dict['%MIDITYPE%'] = "coremidi"
diff --git a/gtk2_ardour/SConscript b/gtk2_ardour/SConscript
index b58b94433c..8a34bf53f9 100644
--- a/gtk2_ardour/SConscript
+++ b/gtk2_ardour/SConscript
@@ -80,6 +80,10 @@ audiounit_files=Split("""
au_pluginui.cc
""")
+gtkosx_files=Split("""
+sync-menu.c
+""")
+
gtkardour_files=Split("""
about.cc
actions.cc
@@ -247,10 +251,13 @@ if env['VST']:
extra_sources += vst_files
gtkardour.Append (CCFLAGS="-DVST_SUPPORT", CPPPATH="#libs/fst")
+if gtkardour['GTKOSX']:
+ extra_sources += gtkosx_files
+ gtkardour.Append (CCFLAGS="-DTOP_MENUBAR -DGTKOSX")
+
if gtkardour['AUDIOUNITS']:
extra_sources += audiounit_files
gtkardour.Append(CCFLAGS='-DHAVE_AUDIOUNITS')
- gtkardour.Append(LINKFLAGS='-framework Carbon')
gtkardour.Merge([libraries['appleutility']])
if env['FFT_ANALYSIS']:
@@ -281,37 +288,37 @@ if gtkardour['DIST_TARGET'] == 'panther' or gtkardour['DIST_TARGET'] == 'tiger':
#
# OS X font rendering is different even with X11
#
- my_font_dict['%FONT_TINY%'] = 'sans 7'
- my_font_dict['%FONT_SMALLERER%'] = 'sans 8'
- my_font_dict['%FONT_SMALLER%'] = 'sans 9'
- my_font_dict['%FONT_SMALL%'] = 'sans 10'
- my_font_dict['%FONT_NORMAL%'] = 'sans 11'
- my_font_dict['%FONT_BIG%'] = 'sans 12'
- my_font_dict['%FONT_BIGGER%'] = 'sans 14'
- my_font_dict['%FONT_LARGE%'] = 'sans 18'
- my_font_dict['%FONT_LARGER%'] = 'sans 28'
- my_font_dict['%FONT_HUGER%'] = 'sans 36'
- my_font_dict['%FONT_MASSIVE%'] = 'sans 60'
- my_font_dict['%FONT_BOLD_TINY%'] = 'sans bold 7'
- my_font_dict['%FONT_BOLD_SMALLER%'] = 'sans bold 9'
- my_font_dict['%FONT_BOLD_SMALL%'] = 'sans bold 10'
- my_font_dict['%FONT_BOLD_NORMAL%'] = 'sans bold 11'
- my_font_dict['%FONT_BOLD_BIG%'] = 'sans bold 13'
- my_font_dict['%FONT_BOLD_BIGGER%'] = 'sans bold 14'
- my_font_dict['%FONT_BOLD_LARGE%'] = 'sans bold 20'
- my_font_dict['%FONT_BOLD_LARGER%'] = 'sans bold 25'
- my_font_dict['%FONT_BOLD_HUGER%'] = 'sans bold 36'
- my_font_dict['%FONT_BOLD_MASSIVE%'] = 'sans bold 60'
- my_font_dict['%FONT_ITALIC_TINY%'] = 'sans italic 7'
- my_font_dict['%FONT_ITALIC_SMALLER%'] = 'sans italic 9'
- my_font_dict['%FONT_ITALIC_SMALL%'] = 'sans italic 10'
- my_font_dict['%FONT_ITALIC_NORMAL%'] = 'sans italic 11'
- my_font_dict['%FONT_ITALIC_BIG%'] = 'sans italic 15'
- my_font_dict['%FONT_ITALIC_BIGGER%'] = 'sans italic 16'
- my_font_dict['%FONT_ITALIC_LARGE%'] = 'sans italic 20'
- my_font_dict['%FONT_ITALIC_LARGER%'] = 'sans italic 28'
- my_font_dict['%FONT_ITALIC_HUGER%'] = 'sans italic 36'
- my_font_dict['%FONT_ITALIC_MASSIVE%'] = 'sans italic 60'
+ my_font_dict['%FONT_TINY%'] = 'Lucida Grande 7'
+ my_font_dict['%FONT_SMALLERER%'] = 'Lucida Grande 8'
+ my_font_dict['%FONT_SMALLER%'] = 'Lucida Grande 9'
+ my_font_dict['%FONT_SMALL%'] = 'Lucida Grande 10'
+ my_font_dict['%FONT_NORMAL%'] = 'Lucida Grande 11'
+ my_font_dict['%FONT_BIG%'] = 'Lucida Grande 12'
+ my_font_dict['%FONT_BIGGER%'] = 'Lucida Grande 14'
+ my_font_dict['%FONT_LARGE%'] = 'Lucida Grande 18'
+ my_font_dict['%FONT_LARGER%'] = 'Lucida Grande 28'
+ my_font_dict['%FONT_HUGER%'] = 'Lucida Grande 36'
+ my_font_dict['%FONT_MASSIVE%'] = 'Lucida Grande 60'
+ my_font_dict['%FONT_BOLD_TINY%'] = 'Lucida Grande bold 7'
+ my_font_dict['%FONT_BOLD_SMALLER%'] = 'Lucida Grande bold 9'
+ my_font_dict['%FONT_BOLD_SMALL%'] = 'Lucida Grande bold 10'
+ my_font_dict['%FONT_BOLD_NORMAL%'] = 'Lucida Grande bold 11'
+ my_font_dict['%FONT_BOLD_BIG%'] = 'Lucida Grande bold 13'
+ my_font_dict['%FONT_BOLD_BIGGER%'] = 'Lucida Grande bold 14'
+ my_font_dict['%FONT_BOLD_LARGE%'] = 'Lucida Grande bold 20'
+ my_font_dict['%FONT_BOLD_LARGER%'] = 'Lucida Grande bold 25'
+ my_font_dict['%FONT_BOLD_HUGER%'] = 'Lucida Grande bold 36'
+ my_font_dict['%FONT_BOLD_MASSIVE%'] = 'Lucida Grande bold 60'
+ my_font_dict['%FONT_ITALIC_TINY%'] = 'Lucida Grande italic 7'
+ my_font_dict['%FONT_ITALIC_SMALLER%'] = 'Lucida Grande italic 9'
+ my_font_dict['%FONT_ITALIC_SMALL%'] = 'Lucida Grande italic 10'
+ my_font_dict['%FONT_ITALIC_NORMAL%'] = 'Lucida Grande italic 11'
+ my_font_dict['%FONT_ITALIC_BIG%'] = 'Lucida Grande italic 15'
+ my_font_dict['%FONT_ITALIC_BIGGER%'] = 'Lucida Grande italic 16'
+ my_font_dict['%FONT_ITALIC_LARGE%'] = 'Lucida Grande italic 20'
+ my_font_dict['%FONT_ITALIC_LARGER%'] = 'Lucida Grande italic 28'
+ my_font_dict['%FONT_ITALIC_HUGER%'] = 'Lucida Grande italic 36'
+ my_font_dict['%FONT_ITALIC_MASSIVE%'] = 'Lucida Grande italic 60'
else:
#
# Linux/X11 font rendering
@@ -428,6 +435,7 @@ env.Alias ('tarball', env.Distribute (env['DISTTREE'],
icon_files +
skipped_files +
audiounit_files +
+ gtkosx_files +
fft_analysis_files +
glob.glob('po/*.po') + glob.glob('*.h')))
diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h
index 4f2d78c736..e712ced9e0 100644
--- a/gtk2_ardour/ardour_ui.h
+++ b/gtk2_ardour/ardour_ui.h
@@ -505,6 +505,8 @@ class ARDOUR_UI : public Gtkmm2ext::UI
Gtk::EventBox menu_bar_base;
Gtk::HBox menu_hbox;
+ void use_menubar_as_top_menubar ();
+
void build_menu_bar ();
void build_control_surface_menu ();
diff --git a/gtk2_ardour/ardour_ui_ed.cc b/gtk2_ardour/ardour_ui_ed.cc
index c04608825e..602fe260ea 100644
--- a/gtk2_ardour/ardour_ui_ed.cc
+++ b/gtk2_ardour/ardour_ui_ed.cc
@@ -37,6 +37,7 @@
#include "engine_dialog.h"
#include "editor.h"
#include "actions.h"
+#include "sync-menu.h"
#include <ardour/session.h>
#include <ardour/profile.h>
@@ -735,7 +736,9 @@ ARDOUR_UI::build_menu_bar ()
sample_rate_box.set_name ("SampleRate");
sample_rate_label.set_name ("SampleRate");
+#ifndef TOP_MENUBAR
menu_hbox.pack_start (*menu_bar, true, true);
+#endif
if (!Profile->get_small_screen()) {
menu_hbox.pack_end (wall_clock_box, false, false, 2);
menu_hbox.pack_end (disk_space_box, false, false, 4);
@@ -744,11 +747,23 @@ ARDOUR_UI::build_menu_bar ()
menu_hbox.pack_end (buffer_load_box, false, false, 4);
menu_hbox.pack_end (sample_rate_box, false, false, 4);
+#ifdef TOP_MENUBAR
+ use_menubar_as_top_menubar ();
+#endif
+
menu_bar_base.set_name ("MainMenuBar");
menu_bar_base.add (menu_hbox);
}
void
+ARDOUR_UI::use_menubar_as_top_menubar ()
+{
+#ifdef GTKOSX
+ sync_menu_takeover_menu ((GtkMenuShell*) menu_bar->gobj());
+#endif
+}
+
+void
ARDOUR_UI::setup_clock ()
{
ARDOUR_UI::Clock.connect (bind (mem_fun (big_clock, &AudioClock::set), false));
diff --git a/gtk2_ardour/sync-menu.c b/gtk2_ardour/sync-menu.c
new file mode 100644
index 0000000000..1f06939ff5
--- /dev/null
+++ b/gtk2_ardour/sync-menu.c
@@ -0,0 +1,795 @@
+/* GTK+ Integration for the Mac OS X Menubar.
+ *
+ * Copyright (C) 2007 Pioneer Research Center USA, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <Carbon/Carbon.h>
+
+#include "sync-menu.h"
+
+#define CARBON_MENU 1
+
+#ifndef CARBON_MENU
+#import <AppKit/AppKit.h>
+#endif
+
+/* TODO
+ *
+ * - Setup shortcuts, possibly transforming ctrl->cmd
+ * - Sync menus
+ * - Create on demand? (can this be done with gtk+? ie fill in menu items when the menu is opened)
+ * - Figure out what to do per app/window...
+ * - Toggle/radio items
+ *
+ */
+
+#define GTK_QUARTZ_MENU_CREATOR 'GTKC'
+#define GTK_QUARTZ_ITEM_WIDGET 'GWID'
+
+
+static void sync_menu_shell (GtkMenuShell *menu_shell,
+ MenuRef carbon_menu);
+
+
+/*
+ * utility functions
+ */
+
+static GtkWidget *
+find_menu_label (GtkWidget *widget)
+{
+ GtkWidget *label = NULL;
+
+ if (GTK_IS_LABEL (widget))
+ return widget;
+
+ if (GTK_IS_CONTAINER (widget))
+ {
+ GList *children;
+ GList *l;
+
+ children = gtk_container_get_children (GTK_CONTAINER (widget));
+
+ for (l = children; l; l = l->next)
+ {
+ label = find_menu_label (l->data);
+ if (label)
+ break;
+ }
+
+ g_list_free (children);
+ }
+
+ return label;
+}
+
+static const gchar *
+get_menu_label_text (GtkWidget *menu_item,
+ GtkWidget **label)
+{
+ *label = find_menu_label (menu_item);
+ if (!*label)
+ return NULL;
+
+ return gtk_label_get_text (GTK_LABEL (*label));
+}
+
+static gboolean
+accel_find_func (GtkAccelKey *key,
+ GClosure *closure,
+ gpointer data)
+{
+ return (GClosure *) data == closure;
+}
+
+
+/*
+ * CarbonMenu functions
+ */
+
+typedef struct
+{
+ MenuRef menu;
+} CarbonMenu;
+
+static GQuark carbon_menu_quark = 0;
+
+static CarbonMenu *
+carbon_menu_new (void)
+{
+ return g_slice_new0 (CarbonMenu);
+}
+
+static void
+carbon_menu_free (CarbonMenu *menu)
+{
+ g_slice_free (CarbonMenu, menu);
+}
+
+static CarbonMenu *
+carbon_menu_get (GtkWidget *widget)
+{
+ return g_object_get_qdata (G_OBJECT (widget), carbon_menu_quark);
+}
+
+static void
+carbon_menu_connect (GtkWidget *menu,
+ MenuRef menuRef)
+{
+ CarbonMenu *carbon_menu = carbon_menu_get (menu);
+
+ if (!carbon_menu)
+ {
+ carbon_menu = carbon_menu_new ();
+
+ g_object_set_qdata_full (G_OBJECT (menu), carbon_menu_quark,
+ carbon_menu,
+ (GDestroyNotify) carbon_menu_free);
+ }
+
+ carbon_menu->menu = menuRef;
+}
+
+
+/*
+ * CarbonMenuItem functions
+ */
+
+typedef struct
+{
+ MenuRef menu;
+ MenuItemIndex index;
+ MenuRef submenu;
+ GClosure *accel_closure;
+} CarbonMenuItem;
+
+static GQuark carbon_menu_item_quark = 0;
+
+static CarbonMenuItem *
+carbon_menu_item_new (void)
+{
+ return g_slice_new0 (CarbonMenuItem);
+}
+
+static void
+carbon_menu_item_free (CarbonMenuItem *menu_item)
+{
+ if (menu_item->accel_closure)
+ g_closure_unref (menu_item->accel_closure);
+
+ g_slice_free (CarbonMenuItem, menu_item);
+}
+
+static CarbonMenuItem *
+carbon_menu_item_get (GtkWidget *widget)
+{
+ return g_object_get_qdata (G_OBJECT (widget), carbon_menu_item_quark);
+}
+
+static void
+carbon_menu_item_update_state (CarbonMenuItem *carbon_item,
+ GtkWidget *widget)
+{
+ gboolean sensitive;
+ gboolean visible;
+ UInt32 set_attrs = 0;
+ UInt32 clear_attrs = 0;
+
+ g_object_get (widget,
+ "sensitive", &sensitive,
+ "visible", &visible,
+ NULL);
+
+ if (!sensitive)
+ set_attrs |= kMenuItemAttrDisabled;
+ else
+ clear_attrs |= kMenuItemAttrDisabled;
+
+ if (!visible)
+ set_attrs |= kMenuItemAttrHidden;
+ else
+ clear_attrs |= kMenuItemAttrHidden;
+
+ ChangeMenuItemAttributes (carbon_item->menu, carbon_item->index,
+ set_attrs, clear_attrs);
+}
+
+static void
+carbon_menu_item_update_active (CarbonMenuItem *carbon_item,
+ GtkWidget *widget)
+{
+ gboolean active;
+
+ g_object_get (widget,
+ "active", &active,
+ NULL);
+
+ CheckMenuItem (carbon_item->menu, carbon_item->index,
+ active);
+}
+
+static void
+carbon_menu_item_update_submenu (CarbonMenuItem *carbon_item,
+ GtkWidget *widget)
+{
+ GtkWidget *submenu;
+
+ submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+
+ if (submenu)
+ {
+ GtkWidget *label = NULL;
+ const gchar *label_text;
+ CFStringRef cfstr = NULL;
+
+ label_text = get_menu_label_text (widget, &label);
+ if (label_text)
+ cfstr = CFStringCreateWithCString (NULL, label_text,
+ kCFStringEncodingUTF8);
+
+ CreateNewMenu (0, 0, &carbon_item->submenu);
+ SetMenuTitleWithCFString (carbon_item->submenu, cfstr);
+ SetMenuItemHierarchicalMenu (carbon_item->menu, carbon_item->index,
+ carbon_item->submenu);
+
+ sync_menu_shell (GTK_MENU_SHELL (submenu), carbon_item->submenu);
+
+ if (cfstr)
+ CFRelease (cfstr);
+ }
+ else
+ {
+ SetMenuItemHierarchicalMenu (carbon_item->menu, carbon_item->index,
+ NULL);
+ carbon_item->submenu = NULL;
+ }
+}
+
+static void
+carbon_menu_item_update_label (CarbonMenuItem *carbon_item,
+ GtkWidget *widget)
+{
+ GtkWidget *label;
+ const gchar *label_text;
+ CFStringRef cfstr = NULL;
+
+ label_text = get_menu_label_text (widget, &label);
+ if (label_text)
+ cfstr = CFStringCreateWithCString (NULL, label_text,
+ kCFStringEncodingUTF8);
+
+ SetMenuItemTextWithCFString (carbon_item->menu, carbon_item->index,
+ cfstr);
+
+ if (cfstr)
+ CFRelease (cfstr);
+}
+
+static void
+carbon_menu_item_update_accelerator (CarbonMenuItem *carbon_item,
+ GtkWidget *widget)
+{
+ GtkWidget *label;
+
+ get_menu_label_text (widget, &label);
+
+ if (GTK_IS_ACCEL_LABEL (label) &&
+ GTK_ACCEL_LABEL (label)->accel_closure)
+ {
+ GtkAccelKey *key;
+
+ key = gtk_accel_group_find (GTK_ACCEL_LABEL (label)->accel_group,
+ accel_find_func,
+ GTK_ACCEL_LABEL (label)->accel_closure);
+
+ if (key &&
+ key->accel_key &&
+ key->accel_flags & GTK_ACCEL_VISIBLE)
+ {
+ GdkDisplay *display = gtk_widget_get_display (widget);
+ GdkKeymap *keymap = gdk_keymap_get_for_display (display);
+ GdkKeymapKey *keys;
+ gint n_keys;
+
+ if (gdk_keymap_get_entries_for_keyval (keymap, key->accel_key,
+ &keys, &n_keys))
+ {
+ UInt8 modifiers = 0;
+
+ SetMenuItemCommandKey (carbon_item->menu, carbon_item->index,
+ true, keys[0].keycode);
+
+ g_free (keys);
+
+ if (key->accel_mods)
+ {
+ if (key->accel_mods & GDK_SHIFT_MASK)
+ modifiers |= kMenuShiftModifier;
+
+ if (key->accel_mods & GDK_MOD1_MASK)
+ modifiers |= kMenuOptionModifier;
+ }
+
+ if (!(key->accel_mods & GDK_CONTROL_MASK))
+ {
+ modifiers |= kMenuNoCommandModifier;
+ }
+
+ SetMenuItemModifiers (carbon_item->menu, carbon_item->index,
+ modifiers);
+
+ return;
+ }
+ }
+ }
+
+ /* otherwise, clear the menu shortcut */
+ SetMenuItemModifiers (carbon_item->menu, carbon_item->index,
+ kMenuNoModifiers | kMenuNoCommandModifier);
+ ChangeMenuItemAttributes (carbon_item->menu, carbon_item->index,
+ 0, kMenuItemAttrUseVirtualKey);
+ SetMenuItemCommandKey (carbon_item->menu, carbon_item->index,
+ false, 0);
+}
+
+static void
+carbon_menu_item_accel_changed (GtkAccelGroup *accel_group,
+ guint keyval,
+ GdkModifierType modifier,
+ GClosure *accel_closure,
+ GtkWidget *widget)
+{
+ CarbonMenuItem *carbon_item = carbon_menu_item_get (widget);
+ GtkWidget *label;
+
+ get_menu_label_text (widget, &label);
+
+ if (GTK_IS_ACCEL_LABEL (label) && GTK_ACCEL_LABEL (label)->accel_closure == accel_closure)
+ carbon_menu_item_update_accelerator (carbon_item, widget);
+}
+
+static void
+carbon_menu_item_update_accel_closure (CarbonMenuItem *carbon_item,
+ GtkWidget *widget)
+{
+ GtkAccelGroup *group;
+ GtkWidget *label;
+
+ get_menu_label_text (widget, &label);
+
+ if (carbon_item->accel_closure)
+ {
+ group = gtk_accel_group_from_accel_closure (carbon_item->accel_closure);
+
+ g_signal_handlers_disconnect_by_func (group,
+ carbon_menu_item_accel_changed,
+ widget);
+
+ g_closure_unref (carbon_item->accel_closure);
+ carbon_item->accel_closure = NULL;
+ }
+
+ if (GTK_IS_ACCEL_LABEL (label))
+ carbon_item->accel_closure = GTK_ACCEL_LABEL (label)->accel_closure;
+
+ if (carbon_item->accel_closure)
+ {
+ g_closure_ref (carbon_item->accel_closure);
+
+ group = gtk_accel_group_from_accel_closure (carbon_item->accel_closure);
+
+ g_signal_connect_object (group, "accel-changed",
+ G_CALLBACK (carbon_menu_item_accel_changed),
+ widget, 0);
+ }
+
+ carbon_menu_item_update_accelerator (carbon_item, widget);
+}
+
+static void
+carbon_menu_item_notify (GObject *object,
+ GParamSpec *pspec,
+ CarbonMenuItem *carbon_item)
+{
+ if (!strcmp (pspec->name, "sensitive") ||
+ !strcmp (pspec->name, "visible"))
+ {
+ carbon_menu_item_update_state (carbon_item, GTK_WIDGET (object));
+ }
+ else if (!strcmp (pspec->name, "active"))
+ {
+ carbon_menu_item_update_active (carbon_item, GTK_WIDGET (object));
+ }
+ else if (!strcmp (pspec->name, "submenu"))
+ {
+ carbon_menu_item_update_submenu (carbon_item, GTK_WIDGET (object));
+ }
+}
+
+static void
+carbon_menu_item_notify_label (GObject *object,
+ GParamSpec *pspec,
+ gpointer data)
+{
+ CarbonMenuItem *carbon_item = carbon_menu_item_get (GTK_WIDGET (object));
+
+ if (!strcmp (pspec->name, "label"))
+ {
+ carbon_menu_item_update_label (carbon_item,
+ GTK_WIDGET (object));
+ }
+ else if (!strcmp (pspec->name, "accel-closure"))
+ {
+ carbon_menu_item_update_accel_closure (carbon_item,
+ GTK_WIDGET (object));
+ }
+}
+
+static CarbonMenuItem *
+carbon_menu_item_connect (GtkWidget *menu_item,
+ GtkWidget *label,
+ MenuRef menu,
+ MenuItemIndex index)
+{
+ CarbonMenuItem *carbon_item = carbon_menu_item_get (menu_item);
+
+ if (!carbon_item)
+ {
+ carbon_item = carbon_menu_item_new ();
+
+ g_object_set_qdata_full (G_OBJECT (menu_item), carbon_menu_item_quark,
+ carbon_item,
+ (GDestroyNotify) carbon_menu_item_free);
+
+ g_signal_connect (menu_item, "notify",
+ G_CALLBACK (carbon_menu_item_notify),
+ carbon_item);
+
+ if (label)
+ g_signal_connect_swapped (label, "notify::label",
+ G_CALLBACK (carbon_menu_item_notify_label),
+ menu_item);
+ }
+
+ carbon_item->menu = menu;
+ carbon_item->index = index;
+
+ return carbon_item;
+}
+
+
+/*
+ * carbon event handler
+ */
+
+static OSStatus
+menu_event_handler_func (EventHandlerCallRef event_handler_call_ref,
+ EventRef event_ref,
+ void *data)
+{
+ UInt32 event_class = GetEventClass (event_ref);
+ UInt32 event_kind = GetEventKind (event_ref);
+ MenuRef menu_ref;
+
+ switch (event_class)
+ {
+ case kEventClassCommand:
+ /* This is called when activating (is that the right GTK+ term?)
+ * a menu item.
+ */
+ if (event_kind == kEventCommandProcess)
+ {
+ HICommand command;
+ OSStatus err;
+
+ //g_print ("Menu: kEventClassCommand/kEventCommandProcess\n");
+
+ err = GetEventParameter (event_ref, kEventParamDirectObject,
+ typeHICommand, 0,
+ sizeof (command), 0, &command);
+
+ if (err == noErr)
+ {
+ GtkWidget *widget = NULL;
+
+ if (command.commandID == kHICommandQuit)
+ {
+ gtk_main_quit (); /* Just testing... */
+ return noErr;
+ }
+
+ /* Get any GtkWidget associated with the item. */
+ err = GetMenuItemProperty (command.menu.menuRef,
+ command.menu.menuItemIndex,
+ GTK_QUARTZ_MENU_CREATOR,
+ GTK_QUARTZ_ITEM_WIDGET,
+ sizeof (widget), 0, &widget);
+ if (err == noErr && widget)
+ {
+ gtk_menu_item_activate (GTK_MENU_ITEM (widget));
+ return noErr;
+ }
+ }
+ }
+ break;
+
+ case kEventClassMenu:
+ GetEventParameter (event_ref,
+ kEventParamDirectObject,
+ typeMenuRef,
+ NULL,
+ sizeof (menu_ref),
+ NULL,
+ &menu_ref);
+
+ switch (event_kind)
+ {
+ case kEventMenuTargetItem:
+ /* This is called when an item is selected (what is the
+ * GTK+ term? prelight?)
+ */
+ //g_print ("kEventClassMenu/kEventMenuTargetItem\n");
+ break;
+
+ case kEventMenuOpening:
+ /* Is it possible to dynamically build the menu here? We
+ * can at least set visibility/sensitivity.
+ */
+ //g_print ("kEventClassMenu/kEventMenuOpening\n");
+ break;
+
+ case kEventMenuClosed:
+ //g_print ("kEventClassMenu/kEventMenuClosed\n");
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ return CallNextEventHandler (event_handler_call_ref, event_ref);
+}
+
+static void
+setup_menu_event_handler (void)
+{
+ EventHandlerUPP menu_event_handler_upp;
+ EventHandlerRef menu_event_handler_ref;
+ const EventTypeSpec menu_events[] = {
+ { kEventClassCommand, kEventCommandProcess },
+ { kEventClassMenu, kEventMenuTargetItem },
+ { kEventClassMenu, kEventMenuOpening },
+ { kEventClassMenu, kEventMenuClosed }
+ };
+
+ /* FIXME: We might have to install one per window? */
+
+ menu_event_handler_upp = NewEventHandlerUPP (menu_event_handler_func);
+ InstallEventHandler (GetApplicationEventTarget (), menu_event_handler_upp,
+ GetEventTypeCount (menu_events), menu_events, 0,
+ &menu_event_handler_ref);
+
+#if 0
+ /* FIXME: Remove the handler with: */
+ RemoveEventHandler(menu_event_handler_ref);
+ DisposeEventHandlerUPP(menu_event_handler_upp);
+#endif
+}
+
+#ifdef CARBON_MENU
+
+static void
+sync_menu_shell (GtkMenuShell *menu_shell,
+ MenuRef carbon_menu)
+{
+ GList *children;
+ GList *l;
+ MenuItemIndex carbon_index = 1;
+
+ carbon_menu_connect (GTK_WIDGET (menu_shell), carbon_menu);
+
+ children = gtk_container_get_children (GTK_CONTAINER (menu_shell));
+
+ for (l = children; l; l = l->next)
+ {
+ GtkWidget *menu_item = l->data;
+ CarbonMenuItem *carbon_item;
+
+ if (GTK_IS_TEAROFF_MENU_ITEM (menu_item))
+ continue;
+
+ carbon_item = carbon_menu_item_get (menu_item);
+
+ if (carbon_item && carbon_item->index != carbon_index)
+ {
+ DeleteMenuItem (carbon_item->menu,
+ carbon_item->index);
+ carbon_item = NULL;
+ }
+
+ if (!carbon_item)
+ {
+ GtkWidget *label = NULL;
+ const gchar *label_text;
+ CFStringRef cfstr = NULL;
+ MenuItemAttributes attributes = 0;
+
+ label_text = get_menu_label_text (menu_item, &label);
+ if (label_text)
+ cfstr = CFStringCreateWithCString (NULL, label_text,
+ kCFStringEncodingUTF8);
+
+ if (GTK_IS_SEPARATOR_MENU_ITEM (menu_item))
+ attributes |= kMenuItemAttrSeparator;
+
+ if (!GTK_WIDGET_IS_SENSITIVE (menu_item))
+ attributes |= kMenuItemAttrDisabled;
+
+ if (!GTK_WIDGET_VISIBLE (menu_item))
+ attributes |= kMenuItemAttrHidden;
+
+ InsertMenuItemTextWithCFString (carbon_menu, cfstr,
+ carbon_index + 1,
+ attributes, 0);
+ SetMenuItemProperty (carbon_menu, carbon_index,
+ GTK_QUARTZ_MENU_CREATOR,
+ GTK_QUARTZ_ITEM_WIDGET,
+ sizeof (menu_item), &menu_item);
+
+ if (cfstr)
+ CFRelease (cfstr);
+
+ carbon_item = carbon_menu_item_connect (menu_item, label,
+ carbon_menu,
+ carbon_index);
+
+ if (GTK_IS_CHECK_MENU_ITEM (menu_item))
+ carbon_menu_item_update_active (carbon_item, menu_item);
+
+ carbon_menu_item_update_accel_closure (carbon_item, menu_item);
+
+ if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu_item)))
+ carbon_menu_item_update_submenu (carbon_item, menu_item);
+ }
+
+ carbon_index++;
+ }
+
+ g_list_free (children);
+}
+
+void
+sync_menu_takeover_menu (GtkMenuShell *menu_shell)
+{
+ MenuRef carbon_menubar;
+
+ g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
+
+ if (carbon_menu_quark == 0)
+ carbon_menu_quark = g_quark_from_static_string ("CarbonMenu");
+
+ if (carbon_menu_item_quark == 0)
+ carbon_menu_item_quark = g_quark_from_static_string ("CarbonMenuItem");
+
+ CreateNewMenu (0 /*id*/, 0 /*options*/, &carbon_menubar);
+ SetRootMenu (carbon_menubar);
+
+ setup_menu_event_handler ();
+
+ sync_menu_shell (menu_shell, carbon_menubar);
+}
+
+#else /* !CARBON_MENU */
+
+static void
+nsmenu_from_menushell (GtkMenuShell *menu_shell,
+ NSMenu *nsMenu)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ GList *children;
+ GList *list;
+
+ children = gtk_container_get_children (GTK_CONTAINER (menu_shell));
+
+ for (list = children; list; list = list->next)
+ {
+ GtkMenuItem *menu_item = list->data;
+ GtkLabel *label;
+ NSMenuItem *menuItem;
+ const gchar *menu_label;
+ NSString *menuLabel;
+ GtkWidget *submenu;
+
+ if (GTK_IS_TEAROFF_MENU_ITEM (menu_item))
+ continue;
+
+ menu_label = get_menu_label_text (menu_item, &label);
+ if (menu_label)
+ menuLabel = [NSString stringWithUTF8String:menu_label];
+ else
+ menuLabel = NULL;
+
+ if (GTK_IS_SEPARATOR_MENU_ITEM (menu_item))
+ menuItem = [NSMenuItem separatorItem];
+ else
+ menuItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] init];
+
+ if (menuLabel)
+ [menuItem setTitle:menuLabel];
+
+ if (!GTK_WIDGET_IS_SENSITIVE (menu_item))
+ [menuItem setEnabled:NO];
+
+#if 0
+ /* FIXME ??? */
+ if (!GTK_WIDGET_VISIBLE (menu_item))
+ /* ??? */;
+#endif
+
+ [nsMenu addItem:menuItem];
+
+ submenu = gtk_menu_item_get_submenu (menu_item);
+ if (submenu)
+ {
+ NSMenu *subMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:menuLabel];
+
+ [menuItem setSubmenu:subMenu];
+
+ nsmenu_from_menushell (GTK_MENU_SHELL (submenu), subMenu);
+ }
+
+#if 0
+ g_signal_connect (menu_item, "notify",
+ G_CALLBACK (menu_item_notify_cb),
+ NULL);
+#endif
+ }
+
+ g_list_free (children);
+
+ [pool release];
+}
+
+void
+sync_menu_takeover_menu (GtkMenuShell *menu_shell)
+{
+ NSMenu *mainMenu;
+
+ g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
+
+ mainMenu = [[NSMenu alloc] initWithTitle:@""];
+
+ // [mainMenu initWithTitle:[NSString stringWithUTF8String:"Foo"]];
+ // [mainMenu setAutoenablesItems:NO];
+
+ // mainMenu = [NSApp mainMenu];
+
+ nsmenu_from_menushell (menu_shell, mainMenu);
+
+ // [NSApp setMainMenu:mainMenu];
+}
+
+#endif /* CARBON_MENU */
diff --git a/gtk2_ardour/sync-menu.h b/gtk2_ardour/sync-menu.h
new file mode 100644
index 0000000000..0715a31e29
--- /dev/null
+++ b/gtk2_ardour/sync-menu.h
@@ -0,0 +1,27 @@
+/* GTK+ Integration for the Mac OS X Menubar.
+ *
+ * Copyright (C) 2007 Pioneer Research Center USA, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+void sync_menu_takeover_menu (GtkMenuShell *menu_shell);
+
+G_END_DECLS