--- gtk/gtkmenubar.c.old	2006-07-03 08:25:06.000000000 +0800
+++ gtk/gtkmenubar.c	2006-08-27 17:36:23.000000000 +0800
@@ -38,6 +38,15 @@
 #include "gtkwindow.h"
 #include "gtkprivate.h"
 #include "gtkalias.h"
+// For mac menubar
+#include "gdk/x11/gdkx.h"
+#include "gtkbox.h"
+#include "gtkdrawingarea.h"
+#include "gtkhbox.h"
+#include "gtklabel.h"
+#include <stdlib.h>
+#include <string.h>
+#include <X11/Xlib.h>
 
 
 #define BORDER_SPACING  0
@@ -55,6 +64,21 @@
 {
   GtkPackDirection pack_direction;
   GtkPackDirection child_pack_direction;
+  /*
+   * Private variables for Mac menubar
+   * +----- mbar_toplevel_width ---------------------------+
+   * | +---- mbar_container -----------------------------+ |
+   * | |  **menubar**                | mbar_title_widget | |
+   * | +-------------------------------------------------+ |
+   * +-----------------------------------------------------+
+   */
+  GtkWindow*       orig_toplevel_win;    // original window, obtained in map()
+  GtkWindow*       mbar_toplevel_win;    // could be NULL, if disabled
+  GtkBox*          mbar_container;
+  GtkWidget*       mbar_title_widget;
+  gint             mbar_toplevel_width;  // used by mbar_toplevel_on_event_after()
+  gint             mbar_toplevel_height; // used by mbar_toplevel_on_event_after()
+  gboolean         in_mbar_toplevel;     // whether the pointer is inside mbar_toplevel_win
 };
 
 #define GTK_MENU_BAR_GET_PRIVATE(o)  \
@@ -89,9 +113,433 @@
 
 G_DEFINE_TYPE (GtkMenuBar, gtk_menu_bar, GTK_TYPE_MENU_SHELL)
 
+
+/*
+ * Mac Menubar options
+ */
+
+static gboolean option_no_mac()
+{
+  char* no_mac_env = "GTK_MENUBAR_NO_MAC";
+  if (! getenv(no_mac_env)) return FALSE;
+  if (! strcmp(getenv(no_mac_env), "1"))
+    return TRUE;
+  else
+    return FALSE;
+}
+
+static gboolean option_keep_docking()
+{
+  char* keep_env = "GTK_MENUBAR_KEEP_DOCKING";
+  if (! getenv(keep_env)) return FALSE;
+  if (! strcmp(getenv(keep_env), "1"))
+    return TRUE;
+  else
+    return FALSE;
+}
+
+static double option_active_opacity()
+{
+  char* opacity_env = "GTK_MENUBAR_ACTIVE_OPACITY";
+  double opacity = 1.0;
+  if (getenv(opacity_env)) opacity = strtod(getenv(opacity_env), 0);
+  return opacity;
+}
+
+static double option_inactive_opacity()
+{
+  char* opacity_env = "GTK_MENUBAR_INACTIVE_OPACITY";
+  double opacity = 2.0/3.0;
+  if (getenv(opacity_env)) opacity = strtod(getenv(opacity_env), 0);
+  return opacity;
+}
+
+static int option_title_width ()
+{
+  char* width_env = "GTK_MENUBAR_TITLE_WIDTH";
+  if (! getenv(width_env))
+    return 0;
+  else
+    return atoi(getenv(width_env));
+}
+
+static const char* option_title_font ()
+{
+  char* font_env = "GTK_MENUBAR_TITLE_FONT";
+  if (! getenv(font_env))
+    return "Times";
+  else
+    return getenv(font_env);
+}
+
+
+/*
+ * Mac Menubar utility functions
+ */
+
+static void gdk_color_to_doubles (GdkColor color, double* output)
+{
+  const int R=0, G=1, B=2;
+  output[R] = color.red / 65535.0;
+  output[G] = color.green / 65535.0;
+  output[B] = color.blue / 65535.0;
+}
+
+/*
+ * Mac Menubar non-callback functions
+ */
+
+static void mbar_toplevel_set_opacity (GtkMenuBar* menubar, double opacity)
+{
+  GtkMenuBarPrivate* priv = GTK_MENU_BAR_GET_PRIVATE (menubar);
+  opacity *= 0xFFFFFFFF;
+  guint opa = (guint) opacity;
+  gdk_property_change (GTK_WIDGET (priv->mbar_toplevel_win)->window,
+                       gdk_atom_intern ("_NET_WM_WINDOW_OPACITY", FALSE),
+                       gdk_atom_intern ("CARDINAL", FALSE), 32,
+                       GDK_PROP_MODE_REPLACE, (guchar *) & opa, 1L);
+}
+
+static void mbar_toplevel_update_strut (GtkMenuBar* menubar)
+{
+  GtkMenuBarPrivate* priv = GTK_MENU_BAR_GET_PRIVATE (menubar);
+  gint width, height;
+  /* _NET_WM_STRUT_PARTIAL: CARDINAL[12]/32
+     *
+     * 0: left          1: right       2:  top             3:  bottom
+     * 4: left_start_y  5: left_end_y  6:  right_start_y   7:  right_end_y
+     * 8: top_start_x   9: top_end_x   10: bottom_start_x  11: bottom_end_x
+     *
+     * Note: In xinerama use struts relative to combined screen dimensions,
+     *       not just the current monitor.
+     */
+  gulong data[12] = { 0, };
+  gtk_window_get_size (priv->mbar_toplevel_win, &width, &height);
+  data[2] = height; data[9] = width;
+  //printf ("set strut %dx%d on top edge\n", width, height);
+  gdk_property_change (GTK_WIDGET (priv->mbar_toplevel_win)->window,
+                       gdk_atom_intern ("_NET_WM_STRUT_PARTIAL", FALSE),
+                       gdk_atom_intern ("CARDINAL", FALSE), 32,
+                       GDK_PROP_MODE_REPLACE, (guchar *) data, 12);
+  gdk_property_change (GTK_WIDGET (priv->mbar_toplevel_win)->window,
+                       gdk_atom_intern ("_NET_WM_STRUT", FALSE),
+                       gdk_atom_intern ("CARDINAL", FALSE), 32,
+                       GDK_PROP_MODE_REPLACE, (guchar *) data, 4);
+}
+
+static void mbar_toplevel_set_enter (GtkMenuBar* menubar)
+{
+  GtkMenuBarPrivate* priv = GTK_MENU_BAR_GET_PRIVATE (menubar);
+  //printf ("enter\n");
+  mbar_toplevel_set_opacity (menubar, option_active_opacity());
+  priv->in_mbar_toplevel = TRUE;
+}
+
+static void mbar_toplevel_set_leave (GtkMenuBar* menubar)
+{
+  GtkMenuBarPrivate* priv = GTK_MENU_BAR_GET_PRIVATE (menubar);
+  //printf ("leave\n");
+  mbar_toplevel_set_opacity (menubar, option_inactive_opacity());
+  priv->in_mbar_toplevel = FALSE;
+}
+
+static void mbar_toplevel_show (GtkMenuBar* menubar)
+{
+  GtkMenuBarPrivate* priv = GTK_MENU_BAR_GET_PRIVATE (menubar);
+  GdkScreen* screen = gtk_window_get_screen (priv->mbar_toplevel_win);
+  GdkGeometry geometry;
+  // Set maximum width and auto height hints
+  geometry.max_width = geometry.min_width = gdk_screen_get_width (screen);
+  geometry.max_height = geometry.min_height = -1;
+  gtk_window_set_geometry_hints (priv->mbar_toplevel_win, GTK_WIDGET (priv->mbar_toplevel_win),
+                                 &geometry, GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
+  //printf ("show\n");
+  if (option_keep_docking())
+  {
+    if (! GTK_WIDGET_VISIBLE (GTK_WIDGET (priv->mbar_toplevel_win)))
+    {
+      gtk_widget_show_all (GTK_WIDGET (priv->mbar_toplevel_win));
+      gtk_window_move (priv->mbar_toplevel_win, 0, 0);
+    }
+    else
+      gtk_widget_show (GTK_WIDGET (priv->mbar_container));
+    mbar_toplevel_set_opacity (menubar, option_inactive_opacity());
+    gtk_window_set_keep_above (priv->mbar_toplevel_win, TRUE);
+  }
+  else
+  {
+    gtk_widget_show_all (GTK_WIDGET (priv->mbar_toplevel_win));
+    gdk_window_show_unraised (GTK_WIDGET (priv->mbar_toplevel_win)->window);
+    gtk_window_move (priv->mbar_toplevel_win, 0, 0);
+  }
+}
+
+static void mbar_toplevel_hide (GtkMenuBar* menubar)
+{
+  GtkMenuBarPrivate* priv = GTK_MENU_BAR_GET_PRIVATE (menubar);
+  //printf ("hide\n");
+  if (option_keep_docking())
+  {
+    mbar_toplevel_set_opacity (menubar, 0.0);
+    gtk_window_set_keep_above (priv->mbar_toplevel_win, FALSE);
+    gtk_widget_hide (GTK_WIDGET (priv->mbar_container));
+  }
+  else
+  {
+    gdk_window_hide (GTK_WIDGET (priv->mbar_toplevel_win)->window);
+    gtk_widget_hide_all (GTK_WIDGET (priv->mbar_toplevel_win));
+  }
+}
+
+static GtkWidget* mbar_title_create ()
+{
+  return gtk_drawing_area_new ();
+}
+
+static void mbar_title_update (GtkMenuBar* menubar, cairo_t* cairo)
+{
+  GtkMenuBarPrivate* priv = GTK_MENU_BAR_GET_PRIVATE (menubar);
+  cairo_pattern_t* pat;
+  cairo_font_options_t* fopt;
+  cairo_matrix_t mtrx;
+  const double margin_width = 3, margin_height = 2, pad_width = 3;
+  double x = margin_width;
+  double y = margin_height;
+  double width = priv->mbar_title_widget->allocation.width - margin_width*2;
+  double height = priv->mbar_title_widget->allocation.height - margin_height*2;
+  const char* text = gtk_window_get_title (priv->orig_toplevel_win);
+  const int R=0, G=1, B=2;
+  GtkStyle* style = GTK_WIDGET (menubar)->style;
+  double bg_left[3]; double bg_right[3];
+  double fg_left[3]; double fg_right[3];
+  double dark[3] = {0.0, 0.0, 0.0};
+  //printf ("update rect (%f, %f) %fx%f\n", x, y, width, height);
+  // Set color
+  gdk_color_to_doubles (style->base[GTK_STATE_SELECTED], bg_left);
+  gdk_color_to_doubles (style->base[GTK_STATE_NORMAL],   bg_right);
+  gdk_color_to_doubles (style->text[GTK_STATE_SELECTED], fg_left);
+  gdk_color_to_doubles (style->text[GTK_STATE_NORMAL],   fg_right);
+  // Make padding
+  cairo_rectangle (cairo, x, y, width, height);
+  cairo_clip (cairo);
+  // Translate matrix
+  cairo_translate (cairo, x, y);
+  cairo_get_matrix (cairo, &mtrx);
+  // Normalize for background (1x1)
+  cairo_scale (cairo, width, height);
+  // Drawing background
+  pat = cairo_pattern_create_linear (0.0, 0.0, 1.0, 0.0);
+  cairo_pattern_set_filter (pat, CAIRO_FILTER_BEST);
+  cairo_pattern_add_color_stop_rgb (pat, 0.0, bg_left[R], bg_left[G], bg_left[B]);
+  cairo_pattern_add_color_stop_rgb (pat, 1.0, bg_right[R], bg_right[G], bg_right[B]);
+  cairo_rectangle (cairo, 0.0, 0.0, 1.0, 1.0);
+  cairo_set_source (cairo, pat);
+  cairo_fill (cairo);
+  cairo_pattern_destroy (pat);
+  // Normalize for text (?x1, lock ratio)
+  cairo_set_matrix (cairo, &mtrx);
+  cairo_translate (cairo, pad_width, 0);
+  cairo_scale (cairo, height, height);
+  // Render title
+  cairo_select_font_face (cairo, option_title_font(),
+                          CAIRO_FONT_SLANT_ITALIC,
+                          CAIRO_FONT_WEIGHT_NORMAL);
+  fopt = cairo_font_options_create();
+  cairo_font_options_set_antialias (fopt, CAIRO_ANTIALIAS_GRAY);
+  cairo_font_options_set_hint_style (fopt, CAIRO_HINT_STYLE_SLIGHT);
+  cairo_font_options_set_hint_metrics (fopt, CAIRO_HINT_METRICS_ON);
+  cairo_set_font_options (cairo, fopt);
+  cairo_set_font_size (cairo, 0.8);
+  // Draw shadow
+  cairo_set_source_rgba (cairo, dark[R], dark[G], dark[B], 0.75);
+  cairo_move_to (cairo, 0.1, 0.8);
+  cairo_show_text (cairo, text);
+  // Draw main text
+  pat = cairo_pattern_create_linear (0.0, 0.0, width/height, 0.0);
+  cairo_pattern_set_filter (pat, CAIRO_FILTER_BEST);
+  cairo_pattern_add_color_stop_rgb (pat, 0.0, fg_left[R], fg_left[G], fg_left[B]);
+  cairo_pattern_add_color_stop_rgb (pat, 1.0, fg_right[R], fg_right[G], fg_right[B]);
+  cairo_set_source (cairo, pat);
+  cairo_move_to (cairo, 0.0, 0.75);
+  cairo_show_text (cairo, text);
+  cairo_pattern_destroy (pat);
+  // Cleanup
+  cairo_font_options_destroy (fopt);
+}
+
+
+/*
+ * Mac Menubar event handlers/callbacks
+ */
+
+static void orig_toplevel_on_event_after (GtkWidget*  widget,
+                                          GdkEvent*   event,
+                                          gpointer    my_data)
+{
+  GtkMenuBar* menubar = (GtkMenuBar*) my_data;
+  GtkMenuBarPrivate* priv = GTK_MENU_BAR_GET_PRIVATE (menubar);
+  if (! priv->mbar_toplevel_win) return;
+  if (event->type == GDK_FOCUS_CHANGE && !priv->in_mbar_toplevel)
+  {
+    if (event->focus_change.in)
+      mbar_toplevel_show (menubar);
+    else
+      mbar_toplevel_hide (menubar);
+  }
+}
+
+static void orig_toplevel_on_title_change (GtkWidget*   widget,
+                                           GParamSpec*  arg,
+                                           gpointer     my_data)
+{
+  GtkMenuBar* menubar = (GtkMenuBar*) my_data;
+  GtkMenuBarPrivate* priv = GTK_MENU_BAR_GET_PRIVATE (menubar);
+  cairo_t* cr = gdk_cairo_create (priv->mbar_title_widget->window);
+  mbar_title_update (menubar, cr);
+  cairo_destroy (cr);
+}
+
+static gboolean orig_toplevel_on_destroy (GtkWidget *widget, gpointer my_data)
+{
+  GtkMenuBar* menubar = (GtkMenuBar*) my_data;
+  GtkMenuBarPrivate* priv = GTK_MENU_BAR_GET_PRIVATE (menubar);
+  if (priv->mbar_toplevel_win)
+  {
+    gtk_widget_destroy (GTK_WIDGET (priv->mbar_toplevel_win));
+    priv->mbar_toplevel_win = 0;
+    priv->mbar_toplevel_width = -1;
+    priv->mbar_toplevel_height = -1;
+    priv->orig_toplevel_win = 0;
+  }
+  return FALSE;
+}
+
+static void mbar_toplevel_on_event_after (GtkWidget*  widget,
+                                          GdkEvent*   event,
+                                          gpointer    my_data)
+{
+  GtkMenuBar* menubar = (GtkMenuBar*) my_data;
+  GtkMenuBarPrivate* priv = GTK_MENU_BAR_GET_PRIVATE (menubar);
+
+  if (event->type == GDK_ENTER_NOTIFY
+      && event->crossing.detail != GDK_NOTIFY_INFERIOR
+      && GTK_WIDGET_VISIBLE (GTK_WIDGET (/*menubar*/priv->mbar_container)))
+  {
+    mbar_toplevel_set_enter (menubar);
+  }
+  else if (event->type == GDK_LEAVE_NOTIFY
+           && event->crossing.detail != GDK_NOTIFY_INFERIOR
+           && GTK_WIDGET_VISIBLE (GTK_WIDGET (/*menubar*/priv->mbar_container)))
+  {
+    mbar_toplevel_set_leave (menubar);
+  }
+  else if (event->type == GDK_CONFIGURE)
+  {
+    //printf ("size changed (%d, %d)\n", event->configure.width, event->configure.height);
+    if (event->configure.width != priv->mbar_toplevel_width
+        || event->configure.height != priv->mbar_toplevel_height)
+    {
+      priv->mbar_toplevel_width = event->configure.width;
+      priv->mbar_toplevel_height = event->configure.height;
+      if (option_keep_docking())
+        mbar_toplevel_update_strut (menubar);
+    }
+  }
+}
+
+static gboolean mbar_title_on_expose (GtkWidget*       widget,
+                                      GdkEventExpose*  event,
+                                      gpointer         my_data)
+{
+  GtkMenuBar* menubar = (GtkMenuBar*) my_data;
+  GtkMenuBarPrivate* priv = GTK_MENU_BAR_GET_PRIVATE (menubar);
+  cairo_t* cr = gdk_cairo_create (priv->mbar_title_widget->window);
+  cairo_rectangle (cr,
+                   event->area.x, event->area.y,
+                   event->area.width, event->area.height);
+  /*printf ("expose rect (%d, %d) %dx%d\n",
+          event->area.x, event->area.y,
+          event->area.width, event->area.height);*/
+  cairo_clip (cr);
+  mbar_title_update (menubar, cr);
+  cairo_destroy (cr);
+  return FALSE;
+}
+
+static void menubar_on_deactivate (GtkMenuShell*  menushell,
+                                   gpointer       my_data)
+{
+  GtkMenuBar* menubar = (GtkMenuBar*) my_data;
+  //printf ("deactivate\n");
+  mbar_toplevel_set_leave (menubar);
+}
+
+static void gtk_menu_bar_map (GtkWidget *widget)
+{
+  GtkMenuBar* menubar = GTK_MENU_BAR (widget);
+  GtkMenuBarPrivate* priv = GTK_MENU_BAR_GET_PRIVATE (menubar);
+
+  if (!priv->mbar_toplevel_win && !option_no_mac())
+    {
+      // Setup menubar's original top-level window
+      priv->orig_toplevel_win
+        = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (menubar)));
+      g_signal_connect (GTK_WIDGET (priv->orig_toplevel_win), "destroy",
+                        G_CALLBACK (orig_toplevel_on_destroy), menubar);
+      g_signal_connect (GTK_WIDGET (priv->orig_toplevel_win), "event-after",
+                        G_CALLBACK (orig_toplevel_on_event_after), menubar);
+      if (option_title_width() > 0)
+      {
+        g_signal_connect (GTK_WIDGET (priv->orig_toplevel_win), "notify::title",
+                          G_CALLBACK (orig_toplevel_on_title_change), menubar);
+      }
+      // Create new top-level window for menubar
+      priv->mbar_toplevel_win
+        = GTK_WINDOW (gtk_window_new (GTK_WINDOW_TOPLEVEL));
+      gtk_window_set_title (priv->mbar_toplevel_win, "GTK MENUBAR");
+      gtk_window_set_resizable (priv->mbar_toplevel_win, FALSE);
+      gtk_window_set_decorated (priv->mbar_toplevel_win, FALSE);
+      gtk_window_set_has_frame (priv->mbar_toplevel_win, FALSE);
+      gtk_window_set_type_hint (priv->mbar_toplevel_win,
+                                GDK_WINDOW_TYPE_HINT_DOCK);
+      g_signal_connect (GTK_WIDGET (priv->mbar_toplevel_win), "event-after",
+                        G_CALLBACK (mbar_toplevel_on_event_after), menubar);
+      // Add a hbox to the new top-level window
+      priv->mbar_container = GTK_BOX (gtk_hbox_new (FALSE, 0));
+      gtk_container_add (GTK_CONTAINER (priv->mbar_toplevel_win),
+                         GTK_WIDGET (priv->mbar_container));
+      // Menubar
+      g_signal_connect (GTK_MENU_SHELL (menubar), "deactivate",
+                        G_CALLBACK (menubar_on_deactivate), menubar);
+      gtk_widget_reparent (GTK_WIDGET (menubar),
+                           GTK_WIDGET (priv->mbar_container));
+      // Add a label to menubar container
+      if (option_title_width() > 0)
+      {
+        priv->mbar_title_widget = mbar_title_create ();
+        gtk_widget_set_size_request (priv->mbar_title_widget,
+                                     option_title_width(), -1);
+        gtk_box_pack_start (priv->mbar_container, priv->mbar_title_widget,
+                            FALSE, FALSE, 0);
+        g_signal_connect (priv->mbar_title_widget, "expose-event",
+                          G_CALLBACK (mbar_title_on_expose), menubar);
+      }
+      // Show everything!
+      mbar_toplevel_show (menubar);
+    }
+
+  (* GTK_WIDGET_CLASS (gtk_menu_bar_parent_class)->map) (GTK_WIDGET (menubar));
+}
+
 static void
 gtk_menu_bar_init (GtkMenuBar *object)
 {
+  GtkMenuBarPrivate* priv = GTK_MENU_BAR_GET_PRIVATE (object);
+  priv->mbar_toplevel_win = 0;
+  priv->orig_toplevel_win = 0;
+  priv->in_mbar_toplevel = FALSE;
+  priv->mbar_toplevel_width = -1;
+  priv->mbar_toplevel_height = -1;
 }
 
 static void
@@ -114,6 +562,7 @@
   widget_class->size_allocate = gtk_menu_bar_size_allocate;
   widget_class->expose_event = gtk_menu_bar_expose;
   widget_class->hierarchy_changed = gtk_menu_bar_hierarchy_changed;
+  widget_class->map = gtk_menu_bar_map;
   
   menu_shell_class->submenu_placement = GTK_TOP_BOTTOM;
   menu_shell_class->get_popup_delay = gtk_menu_bar_get_popup_delay;
