Drop shadow madness



Okay,
First off
I don't expect to see this committed.
Ever.
It's a hack.
There's even a hack inside the hack
Thats how hacky this hacky hack is.

But I've been using it for a week now
And I love it.
It seems to add a modicum of class
And style to my otherwise dreery drab desktop.

So I am sharing it with the rest of the world.
But, like I say
It's a hack.
There's occasions where it won't look right.
And those occasions will never look right
With this hack.
I know about them
I don't care about them.
If it breaks - 
Congratulations, you get to keep all the bits.

And so, without further ado...
I give you
the gtkmenu drop shadow hack

Taadaa!
(and yes, I nicked the arrays of values off of kde-look.org
 which means that if you apply that patch to your KDE, then
 the two drop shadows will look the same)

Enjoy
iain
-- 
Index: gtkmenu.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmenu.c,v
retrieving revision 1.129
diff -U2 -r1.129 gtkmenu.c
--- gtkmenu.c	5 Feb 2003 23:48:09 -0000	1.129
+++ gtkmenu.c	16 Feb 2003 14:35:07 -0000
@@ -75,4 +75,7 @@
   gint x;
   gint y;
+  GdkPixbuf *west, *east, *south;
+  GdkWindow *west_shadow, *east_shadow, *south_shadow;
+  guint32 timeout_id;
 };
 
@@ -182,4 +185,24 @@
 static guint menu_signals[LAST_SIGNAL] = { 0 };
 
+static void
+free_private_data (gpointer data)
+{
+  GtkMenuPrivate *priv = (GtkMenuPrivate *) data;
+
+  if (priv->timeout_id > 0) 
+    g_source_remove (priv->timeout_id);
+  
+  if (priv->west)
+    g_object_unref (G_OBJECT (priv->west));
+
+  if (priv->east)
+    g_object_unref (G_OBJECT (priv->east));
+
+  if (priv->south)
+    g_object_unref (G_OBJECT (priv->south));
+
+  g_free (data);
+}
+
 GtkMenuPrivate *
 gtk_menu_get_private (GtkMenu *menu)
@@ -199,5 +222,5 @@
       
       g_object_set_qdata_full (G_OBJECT (menu), private_quark,
-			       private, g_free);
+			       private, free_private_data);
     }
 
@@ -232,4 +255,349 @@
 }
 
+static GdkPixbuf *
+get_pixbuf (GdkDrawable *window,
+	    int x,
+	    int y,
+	    int width,
+	    int height)
+{
+  GdkPixbuf *dest, *src;
+  int ow, oh;
+  
+  dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height);
+
+  ow = width;
+  oh = height;
+  
+  if (x < 0) {
+    width += x;
+    x = 0;
+  }
+
+  if (y < 0) {
+    height += y;
+    y = 0;
+  }
+
+  if (width <= 0 || height <= 0)
+    return NULL;
+
+  window = gdk_get_default_root_window ();
+
+  src = gdk_pixbuf_get_from_drawable (NULL, window, NULL, x, y, 0, 0, width, height);
+
+  /* Copy the src into the dest at the right place */
+  gdk_pixbuf_copy_area (src, 0, 0, width, height,
+			dest, ow - width, oh - height);
+
+  g_object_unref (G_OBJECT (src));
+  
+  return dest;
+}
+
+enum side {
+  WEST_SIDE,
+  EAST_SIDE,
+  SOUTH_SIDE
+};
+
+const double shadow_strip_l[16] = {
+  .996, .996, .992, .988, .980, .972, .956, .941, .917, .890, .858, .819, .776, .729, .678, .627
+};
+
+const double bottom_left_corner[256] =	{
+  .996, .996, .992, .988, .980, .972, .956, .941, .917, .890, .858, .819, .776, .729, .678, .627, 
+  .996, .996, .992, .988, .980, .972, .956, .941, .917, .890, .858, .819, .776, .729, .678, .627, 
+  .996, .996, .992, .988, .980, .972, .956, .941, .917, .890, .858, .819, .776, .729, .678, .627, 
+  .996, .996, .992, .988, .980, .972, .956, .941, .917, .890, .858, .819, .776, .729, .678, .627, 
+  .996, .996, .992, .988, .980, .972, .956, .941, .917, .890, .858, .819, .776, .729, .678, .627, 
+  1.00, .996, .992, .988, .980, .972, .960, .941, .917, .890, .858, .819, .780, .733, .670, .643, 
+  1.00, .996, .992, .988, .980, .972, .960, .941, .917, .894, .858, .819, .780, .733, .670, .643, 
+  1.00, .996, .992, .988, .980, .972, .960, .941, .921, .894, .862, .827, .784, .737, .690, .639, 
+  1.00, .996, .992, .988, .980, .972, .960, .945, .925, .898, .870, .831, .796, .749, .701, .654, 
+  1.00, .996, .992, .992, .984, .976, .964, .949, .933, .909, .882, .847, .815, .776, .733, .686, 
+  1.00, .996, .992, .992, .988, .980, .972, .956, .941, .925, .901, .874, .847, .811, .780, .741, 
+  1.00, 1.00, .996, .992, .992, .988, .980, .968, .956, .945, .925, .909, .886, .901, .874, .811, 
+  1.00, 1.00, 1.00, .996, .992, .992, .988, .980, .976, .964, .952, .941, .929, .913, .898, .878, 
+  1.00, 1.00, 1.00, 1.00, .996, .996, .996, .992, .988, .984, .976, .968, .964, .952, .945, .937, 
+  1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, .996, .996, .992, .988, .984, .980, .976, .972, 
+  1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, .996, .996, .996, .992, .992, .992 };
+
+const double bottom_right_corner[256] = {
+  .627, .678, .729, .776, .819, .858, .890, .917, .941, .956, .972, .980, .988, .992, .996, .996,
+  .627, .678, .729, .776, .819, .858, .890, .917, .941, .956, .972, .980, .988, .992, .996, .996,
+  .627, .678, .729, .776, .819, .858, .890, .917, .941, .956, .972, .980, .988, .992, .996, .996,
+  .627, .678, .729, .776, .819, .858, .890, .917, .941, .956, .972, .980, .988, .992, .996, .996,
+  .627, .678, .729, .776, .819, .858, .890, .917, .941, .956, .972, .980, .988, .992, .996, .996,
+  .643, .670, .733, .780, .819, .858, .890, .917, .941, .960, .972, .980, .988, .992, .996, 1.00,
+  .643, .670, .733, .780, .819, .858, .894, .917, .941, .960, .972, .980, .988, .992, .996, 1.00,
+  .639, .690, .737, .784, .827, .862, .894, .921, .941, .960, .972, .980, .988, .992, .996, 1.00,
+  .654, .701, .749, .796, .831, .870, .898, .925, .945, .960, .972, .980, .988, .992, .996, 1.00,
+  .686, .733, .776, .815, .847, .882, .909, .933, .949, .964, .976, .984, .992, .992, .996, 1.00,
+  .741, .780, .811, .847, .874, .901, .925, .941, .956, .972, .980, .988, .992, .992, .996, 1.00,
+  .811, .874, .901, .886, .909, .925, .945, .956, .968, .980, .988, .992, .992, .996, 1.00, 1.00,
+  .878, .898, .913, .929, .941, .952, .964, .976, .980, .988, .992, .992, .996, 1.00, 1.00, 1.00,
+  .937, .945, .952, .964, .968, .976, .984, .988, .992, .996, .996, .996, 1.00, 1.00, 1.00, 1.00,
+  .972, .976, .980, .984, .988, .992, .996, .996, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00,
+  .992, .992, .992, .996, .996, .996, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00 };
+
+const double top_right_corner[256] = {
+  .992, .992, .992, .996, .996, .996, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00,
+  .972, .976, .980, .984, .988, .992, .996, .996, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00,
+  .937, .945, .952, .964, .968, .976, .984, .988, .992, .996, .996, .996, 1.00, 1.00, 1.00, 1.00,
+  .878, .898, .913, .929, .941, .952, .964, .976, .980, .988, .992, .992, .996, 1.00, 1.00, 1.00,
+  .811, .874, .901, .886, .909, .925, .945, .956, .968, .980, .988, .992, .992, .996, 1.00, 1.00,
+  .741, .780, .811, .847, .874, .901, .925, .941, .956, .972, .980, .988, .992, .992, .996, 1.00,
+  .686, .733, .776, .815, .847, .882, .909, .933, .949, .964, .976, .984, .992, .992, .996, 1.00,
+  .654, .701, .749, .796, .831, .870, .898, .925, .945, .960, .972, .980, .988, .992, .996, 1.00,
+  .639, .690, .737, .784, .827, .862, .894, .921, .941, .960, .972, .980, .988, .992, .996, 1.00,
+  .643, .670, .733, .780, .819, .858, .894, .917, .941, .960, .972, .980, .988, .992, .996, 1.00,
+  .643, .670, .733, .780, .819, .858, .890, .917, .941, .960, .972, .980, .988, .992, .996, 1.00,
+  .627, .678, .729, .776, .819, .858, .890, .917, .941, .956, .972, .980, .988, .992, .996, .996,
+  .627, .678, .729, .776, .819, .858, .890, .917, .941, .956, .972, .980, .988, .992, .996, .996,
+  .627, .678, .729, .776, .819, .858, .890, .917, .941, .956, .972, .980, .988, .992, .996, .996,
+  .627, .678, .729, .776, .819, .858, .890, .917, .941, .956, .972, .980, .988, .992, .996, .996,
+  .627, .678, .729, .776, .819, .858, .890, .917, .941, .956, .972, .980, .988, .992, .996, .996 };
+
+const double top_left_corner[256] = {
+  1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, .996, .996, .996, .992, .992, .992,
+  1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, .996, .996, .992, .988, .984, .980, .976, .972, 
+  1.00, 1.00, 1.00, 1.00, .996, .996, .996, .992, .988, .984, .976, .968, .964, .952, .945, .937, 
+  1.00, 1.00, 1.00, .996, .992, .992, .988, .980, .976, .964, .952, .941, .929, .913, .898, .878, 
+  1.00, 1.00, .996, .992, .992, .988, .980, .968, .956, .945, .925, .909, .886, .901, .874, .811, 
+  1.00, .996, .992, .992, .988, .980, .972, .956, .941, .925, .901, .874, .847, .811, .780, .741, 
+  1.00, .996, .992, .992, .984, .976, .964, .949, .933, .909, .882, .847, .815, .776, .733, .686, 
+  1.00, .996, .992, .988, .980, .972, .960, .945, .925, .898, .870, .831, .796, .749, .701, .654, 
+  1.00, .996, .992, .988, .980, .972, .960, .941, .921, .894, .862, .827, .784, .737, .690, .639, 
+  1.00, .996, .992, .988, .980, .972, .960, .941, .917, .894, .858, .819, .780, .733, .670, .643, 
+  1.00, .996, .992, .988, .980, .972, .960, .941, .917, .890, .858, .819, .780, .733, .670, .643, 
+  .996, .996, .992, .988, .980, .972, .956, .941, .917, .890, .858, .819, .776, .729, .678, .627, 
+  .996, .996, .992, .988, .980, .972, .956, .941, .917, .890, .858, .819, .776, .729, .678, .627, 
+  .996, .996, .992, .988, .980, .972, .956, .941, .917, .890, .858, .819, .776, .729, .678, .627, 
+  .996, .996, .992, .988, .980, .972, .956, .941, .917, .890, .858, .819, .776, .729, .678, .627, 
+  .996, .996, .992, .988, .980, .972, .956, .941, .917, .890, .858, .819, .776, .729, .678, .627 };
+
+static void
+adjust_pixbuf (GdkPixbuf *pb,
+	       enum side shadow)
+{
+  int width, rowstride, height;
+  int i;
+  guchar *pixels, *p;
+
+  width = gdk_pixbuf_get_width (pb);
+  height = gdk_pixbuf_get_height (pb);
+  rowstride = gdk_pixbuf_get_rowstride (pb);
+  pixels = gdk_pixbuf_get_pixels (pb);
+
+  switch (shadow) {
+  case WEST_SIDE:
+    if (height > 16) {
+      for (i = 0; i < 16; i++) {
+	int j, k;
+	
+	p = pixels + (i * rowstride);
+
+	for (j = 0, k = 0; j < 48; j += 3, k++) {
+	  p[j] = (guchar) (p[j] * top_left_corner [i * 16 + k]);
+	  p[j + 1] = (guchar) (p[j + 1] * top_left_corner [i * 16 + k]);
+	  p[j + 2] = (guchar) (p[j + 2] * top_left_corner [i * 16 + k]);
+	}
+      }
+
+      i = 16;
+    } else {
+      i = 0;
+    }
+	
+    for (; i < height; i++) {
+      int j, k;
+      
+      p = pixels + (i * rowstride);
+
+      for (j = 0, k = 0; j < 48; j += 3, k++) {
+	p[j] = (guchar) (p[j] * shadow_strip_l[k]);
+	p[j + 1] = (guchar) (p[j + 1] * shadow_strip_l[k]);
+	p[j + 2] = (guchar) (p[j + 2] * shadow_strip_l[k]);
+      }
+    }
+
+    break;
+
+  case EAST_SIDE:
+    if (height > 16) {
+      for (i = 0; i < 16; i++) {
+	int j, k;
+
+	p = pixels + (i * rowstride);
+
+	for (j = 0, k = 0; j < 48; j += 3, k++) {
+	  p[j] = (guchar) (p[j] * top_right_corner [i * 16 + k]);
+	  p[j + 1] = (guchar) (p[j + 1] * top_right_corner [i * 16 + k]);
+	  p[j + 2] = (guchar) (p[j + 2] * top_right_corner [i * 16 + k]);
+	}
+      }
+
+      i = 16;
+    } else {
+      i = 0;
+    }
+    
+    for (;i < height; i++) {
+      int j, k;
+
+      p = pixels + (i * rowstride);
+
+      for (j = 0, k = 0; j < 48; j += 3, k++) {
+	p[j] = (guchar) (p[j] * shadow_strip_l[15 - k]);
+	p[j + 1] = (guchar) (p[j + 1] * shadow_strip_l[15 - k]);
+	p[j + 2] = (guchar) (p[j + 2] * shadow_strip_l[15 - k]);
+      }
+    }
+
+    break;
+
+  case SOUTH_SIDE:
+    for (i = 0; i < 16; i++) {
+      int j, k;
+
+      p = pixels + (i * rowstride);
+
+      for (j = 0, k = 0; j < 48; j += 3, k++) {
+
+	p[j] = (guchar) (p[j] * bottom_left_corner[i * 16 + k]);
+	p[j + 1] = (guchar) (p[j + 1] * bottom_left_corner[i * 16 + k]);
+	p[j + 2] = (guchar) (p[j + 2] * bottom_left_corner[i * 16 + k]);
+      }
+
+      p = pixels + (i * rowstride) + 48;
+      
+      for (j = 0, k = 0; j < (width * 3) - 96; j += 3, k++) {
+	p[j] = (guchar) (p[j] * bottom_right_corner [i * 16]);
+	p[j + 1] = (guchar) (p[j + 1] * bottom_right_corner [i * 16]);
+	p[j + 2] = (guchar) (p[j + 2] * bottom_right_corner [i * 16]);
+      }
+
+      p = pixels + (i * rowstride) + ((width * 3) - 48);
+      for (j = 0, k = 0; j < 48; j += 3, k++) {
+	p[j] = (guchar) (p[j] * bottom_right_corner[i * 16 + k]);
+	p[j + 1] = (guchar) (p[j + 1] * bottom_right_corner[i * 16 + k]);
+	p[j + 2] = (guchar) (p[j + 2] * bottom_right_corner[i * 16 + k]);
+      }
+    }
+
+    break;
+
+  default:
+    break;
+  }
+}
+
+static gboolean
+map_shadow_windows (gpointer data)
+{
+  GtkMenu *menu = GTK_MENU (data);
+  GtkWidget *widget = GTK_WIDGET (data);
+  GtkMenuPrivate *priv = gtk_menu_get_private (menu);
+  GdkPixbuf *pixbuf;
+  int tlx, tly;
+
+  gtk_window_get_position (gtk_widget_get_toplevel (widget), &tlx, &tly);
+  pixbuf = get_pixbuf (priv->west_shadow, tlx - 16, tly,
+		       16, widget->allocation.height);
+
+  if (pixbuf != NULL) {
+    adjust_pixbuf (pixbuf, WEST_SIDE);
+    if (priv->west != NULL) {
+      g_object_unref (G_OBJECT (priv->west));
+    }
+    priv->west = pixbuf;
+  }
+  
+  pixbuf = get_pixbuf (priv->east_shadow, tlx + widget->allocation.width,
+		       tly,
+		       16, widget->allocation.height);
+  if (pixbuf != NULL) {
+    adjust_pixbuf (pixbuf, EAST_SIDE);
+    if (priv->east != NULL) {
+      g_object_unref (G_OBJECT (priv->east));
+    }
+    priv->east = pixbuf;
+  }
+  
+  pixbuf = get_pixbuf (priv->south_shadow, tlx - 16,
+		       tly + widget->allocation.height,
+		       widget->allocation.width + 32, 16);
+  if (pixbuf != NULL) {
+    adjust_pixbuf (pixbuf, SOUTH_SIDE);
+    if (priv->south != NULL) {
+      g_object_unref (G_OBJECT (priv->south));
+    }
+    priv->south = pixbuf;
+  }
+
+  gdk_window_show (priv->west_shadow);
+  gdk_window_show (priv->east_shadow);
+  gdk_window_show (priv->south_shadow);
+
+  priv->timeout_id = 0;
+  return FALSE;
+}
+
+static void
+gtk_menu_map (GtkWidget *widget)
+{
+  GtkMenuPrivate *priv = gtk_menu_get_private (GTK_MENU (widget));
+  /* What is this timeout for?
+     Well, its a hack inside a hack really.
+     Sometimes the parent window hasn't had time to redraw fully
+     so you get an ugly drop shadow on a half exposed window.
+     This timeout is an attempt to give the parent window a change
+     to redraw itself fully, so that the drop shadow doesn't look
+     just so ugly... */
+  priv->timeout_id = g_timeout_add (20, map_shadow_windows, widget);
+  
+  GTK_WIDGET_CLASS (parent_class)->map (widget);
+}
+
+static void
+gtk_menu_unmap (GtkWidget *widget)
+{
+  GtkMenu *menu = GTK_MENU (widget);
+  GtkMenuPrivate *priv = gtk_menu_get_private (menu);
+
+  if (priv->timeout_id > 0) {
+    g_source_remove (priv->timeout_id);
+    priv->timeout_id = 0;
+  } else {
+    gdk_window_hide (priv->west_shadow);
+    gdk_window_hide (priv->east_shadow);
+    gdk_window_hide (priv->south_shadow);
+  }
+  
+  GTK_WIDGET_CLASS (parent_class)->unmap (widget);
+}
+
+static gboolean
+gtk_menu_configure (GtkWidget *widget,
+		    GdkEventConfigure *event)
+{
+  GtkMenu *menu;
+  GtkMenuPrivate *priv;
+  int tlx, tly;
+  
+  menu = GTK_MENU (widget);
+  priv = gtk_menu_get_private (menu);
+  
+  /* Move shadows */
+  gtk_window_get_position (gtk_widget_get_toplevel (widget), &tlx, &tly);
+
+  gdk_window_move (priv->west_shadow, tlx - 16, tly);
+  gdk_window_move (priv->east_shadow, tlx + widget->allocation.width, tly);
+  gdk_window_move (priv->south_shadow, tlx - 16, tly + widget->allocation.height);
+  
+  return FALSE;
+}
+
 static void
 gtk_menu_class_init (GtkMenuClass *class)
@@ -280,6 +648,9 @@
   widget_class->show_all = gtk_menu_show_all;
   widget_class->hide_all = gtk_menu_hide_all;
+  widget_class->map = gtk_menu_map;
+  widget_class->unmap = gtk_menu_unmap;
   widget_class->enter_notify_event = gtk_menu_enter_notify;
   widget_class->leave_notify_event = gtk_menu_leave_notify;
+  widget_class->configure_event = gtk_menu_configure;
   widget_class->motion_notify_event = gtk_menu_motion_notify;
   widget_class->style_set = gtk_menu_style_set;
@@ -1005,5 +1376,5 @@
 
   g_return_if_fail (GTK_IS_MENU (menu));
-  
+
   menu_shell = GTK_MENU_SHELL (menu);
   private = gtk_menu_get_private (menu);
@@ -1488,10 +1859,13 @@
   gint border_width;
   GtkMenu *menu;
+  GtkMenuPrivate *priv;
   GtkWidget *child;
   GList *children;
-
+  int tlx, tly;
+  
   g_return_if_fail (GTK_IS_MENU (widget));
 
   menu = GTK_MENU (widget);
+  priv = gtk_menu_get_private (menu);
   
   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
@@ -1559,4 +1933,43 @@
   gdk_window_show (menu->bin_window);
   gdk_window_show (menu->view_window);
+
+  /* Drop shadow */
+
+  gtk_window_get_position (gtk_widget_get_toplevel (widget), &tlx, &tly);
+  
+  /* The West drop shadow window */
+  attributes.x = tlx - 16;
+  attributes.y = tly;
+  attributes.width = 16;
+  attributes.height = widget->allocation.height;
+  attributes.window_type = GDK_WINDOW_TEMP;
+  attributes.override_redirect = TRUE;
+
+  attributes_mask |= GDK_WA_NOREDIR;
+  
+  priv->west_shadow = gdk_window_new (NULL, &attributes, attributes_mask);
+  gdk_window_set_user_data (priv->west_shadow, menu);
+  
+  /* East drop shadow */
+  attributes.x = tlx + widget->allocation.width;
+  attributes.y = tly;
+  attributes.width = 16;
+  attributes.height = widget->allocation.height;
+
+  priv->east_shadow = gdk_window_new (NULL, &attributes, attributes_mask);
+  gdk_window_set_user_data (priv->east_shadow, menu);
+  
+  /* South drop shadow */
+  attributes.x = tlx - 16;
+  attributes.y = tly + widget->allocation.height;
+  attributes.width = widget->allocation.width + 32;
+  attributes.height = 16;
+
+  priv->south_shadow = gdk_window_new (NULL, &attributes, attributes_mask);
+  gdk_window_set_user_data (priv->south_shadow, menu);
+
+  gdk_window_set_back_pixmap (priv->west_shadow, NULL, FALSE);
+  gdk_window_set_back_pixmap (priv->east_shadow, NULL, FALSE);
+  gdk_window_set_back_pixmap (priv->south_shadow, NULL, FALSE);
 }
 
@@ -1621,8 +2034,10 @@
 {
   GtkMenu *menu;
+  GtkMenuPrivate *priv;
 
   g_return_if_fail (GTK_IS_MENU (widget));
 
   menu = GTK_MENU (widget);
+  priv = gtk_menu_get_private (menu);
 
   menu_grab_transfer_window_destroy (menu);
@@ -1636,4 +2051,9 @@
   menu->bin_window = NULL;
 
+  /* Shadows */
+  gdk_window_destroy (priv->west_shadow);
+  gdk_window_destroy (priv->east_shadow);
+  gdk_window_destroy (priv->south_shadow);
+  
   (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
 }
@@ -1745,4 +2165,6 @@
   if (GTK_WIDGET_REALIZED (widget))
     {
+      GtkMenuPrivate *priv = gtk_menu_get_private (menu);
+      
       gdk_window_move_resize (widget->window,
 			      allocation->x, allocation->y,
@@ -1754,4 +2176,8 @@
 			      width,
 			      height);
+
+      gdk_window_resize (priv->west_shadow, 16, allocation->height);
+      gdk_window_resize (priv->east_shadow, 16, allocation->height);
+      gdk_window_resize (priv->south_shadow, 32 + allocation->width, 16);
     }
 
@@ -1909,4 +2335,59 @@
 			   MENU_SCROLL_ARROW_HEIGHT - 2 * border_y - 2);
 	}
+    } else {
+      int width, height;
+      GdkGC *gc = widget->style->black_gc;
+      GtkMenuPrivate *priv = gtk_menu_get_private (menu);
+
+      if (event->window == priv->west_shadow) {
+	if (priv->west == NULL)
+	  return;
+	
+	gdk_gc_set_clip_rectangle (gc, &event->area);
+
+	width = gdk_pixbuf_get_width (priv->west);
+	height = gdk_pixbuf_get_height (priv->west);
+
+	gdk_draw_pixbuf (priv->west_shadow, gc, priv->west, 0, 0, 0, 0,
+			 width, height, GDK_RGB_DITHER_NONE, 0, 0);
+
+	gdk_gc_set_clip_rectangle (gc, NULL);
+
+	return;
+      }
+      
+      if (event->window == priv->east_shadow) {
+	if (priv->east == NULL)
+	  return;
+	
+	gdk_gc_set_clip_rectangle (gc, &event->area);
+
+	width = gdk_pixbuf_get_width (priv->east);
+	height = gdk_pixbuf_get_height (priv->east);
+	
+	gdk_draw_pixbuf (priv->east_shadow, gc, priv->east, 0, 0, 0, 0,
+			 width, height, GDK_RGB_DITHER_NONE, 0, 0);
+
+	gdk_gc_set_clip_rectangle (gc, NULL);
+	return;
+      }
+	
+      if (event->window == priv->south_shadow) {
+	if (priv->south == NULL)
+	  return;
+	
+	gdk_gc_set_clip_rectangle (gc, &event->area);
+
+	width = gdk_pixbuf_get_width (priv->south);
+	height = gdk_pixbuf_get_height (priv->south);
+
+	gdk_draw_pixbuf (priv->south_shadow, gc, priv->south, 0, 0, 0, 0,
+			 width, height, GDK_RGB_DITHER_NONE, 0, 0);
+
+	gdk_gc_set_clip_rectangle (gc, NULL);
+	
+	return;
+      }
+
     }
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]