On Sat, 2003-12-27 at 19:38, Ryan wrote: > Hi, > > Bit of a gtk newbie here sorry if the question is offensive by nature. > Is there a patch for gtk2-menu-dropshadows that's compatible with gtk+ > 2.4 (2.3)? How do (or can) I enable this option when building gtk2? My > favorite theme is quite white and some additional separation would be > nice (yeah I know about freedesktop.org ;-) > > thanks, > -ry You should not attempt to create a new thread by replying to old messages. But yes, there is a patch for gtk+ that adds menu dropshadows - I use it on my system here. As it's only 16K I have also attached it FYI. The source was www.breakmygentoo.net, although I don't know where it originally surfaced. I think it seems a little sluggish to me, but looks quite neat. -- Tom Wesley
--- gtk.orig/gtkmenu.c Tue May 20 21:00:52 2003
+++ gtk/gtkmenu.c Fri Jun 20 00:59:41 2003
@@ -48,6 +48,7 @@
#define DEFAULT_POPUP_DELAY 225
#define DEFAULT_POPDOWN_DELAY 1000
+#define DEFAULT_SHADOW_DELAY 50
#define NAVIGATION_REGION_OVERSHOOT 50 /* How much the navigation region
* extends below the submenu
@@ -74,6 +75,9 @@
gboolean have_position;
gint x;
gint y;
+ GdkPixbuf *east, *south;
+ GdkWindow *east_shadow, *south_shadow;
+ guint32 timeout_id;
};
enum {
@@ -86,6 +90,60 @@
PROP_TEAROFF_TITLE
};
+enum side {
+ EAST_SIDE,
+ SOUTH_SIDE
+};
+
+const double shadow_strip_l[5] = {
+ .937, .831, .670, .478, .180
+};
+
+const double bottom_left_corner[25] = {
+ 1.00, .682, .423, .333, .258,
+ 1.00, .898, .800, .682, .584,
+ 1.00, .937, .874, .800, .737,
+ 1.00, .968, .937, .898, .866,
+ 1.00, .988, .976, .960, .945
+};
+
+const double bottom_right_corner[25] = {
+ .258, .584, .737, .866, .945,
+ .584, .682, .800, .898, .960,
+ .737, .800, .874, .937, .976,
+ .866, .898, .937, .968, .988,
+ .945, .960, .976, .988, .996
+};
+
+const double top_right_corner[25] = {
+ 1.00, 1.00, 1.00, 1.00, 1.00,
+ .686, .898, .937, .968, .988,
+ .423, .803, .874, .937, .976,
+ .333, .686, .800, .898, .960,
+ .258, .584, .737, .866, .945
+};
+
+const double top_left_corner[25] = {
+ .988, .968, .937, .898, .498,
+ .976, .937, .874, .803, .423,
+ .960, .898, .800, .686, .333,
+ .945, .866, .737, .584, .258,
+ .941, .847, .698, .521, .215
+};
+
+static GdkPixbuf *get_pixbuf (GtkMenu *menu,
+ int x,
+ int y,
+ int width,
+ int height);
+static void shadow_paint (GtkWidget *widget,
+ GdkRectangle *area,
+ enum side shadow);
+static void pixbuf_add_shadow (GdkPixbuf *pb,
+ enum side shadow);
+static gboolean map_shadow_windows (gpointer data);
+static void shadow_add_timeout (GtkWidget *widget);
+static void shadow_remove_timeout (GtkWidget *widget);
static void gtk_menu_class_init (GtkMenuClass *klass);
static void gtk_menu_init (GtkMenu *menu);
static void gtk_menu_set_property (GObject *object,
@@ -181,6 +239,17 @@
static guint menu_signals[LAST_SIGNAL] = { 0 };
+static void
+free_private_data (gpointer data)
+{
+ GtkMenuPrivate *private = (GtkMenuPrivate *) data;
+
+ if (private->timeout_id > 0)
+ g_source_remove (private->timeout_id);
+
+ g_free (data);
+}
+
GtkMenuPrivate *
gtk_menu_get_private (GtkMenu *menu)
{
@@ -198,7 +267,7 @@
private->have_position = FALSE;
g_object_set_qdata_full (G_OBJECT (menu), private_quark,
- private, g_free);
+ private, free_private_data);
}
return private;
@@ -231,6 +300,307 @@
return menu_type;
}
+static GdkPixbuf *
+get_pixbuf (GtkMenu *menu,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ GdkPixbuf *dest, *src;
+ GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET(menu));
+ GdkWindow *root = gdk_screen_get_root_window (screen);
+ gint screen_height = gdk_screen_get_height (screen);
+ gint screen_width = gdk_screen_get_width (screen);
+ gint original_width = width;
+ gint original_height = height;
+
+ if (x < 0)
+ {
+ width += x;
+ x = 0;
+ }
+
+ if (y < 0)
+ {
+ height += y;
+ y = 0;
+ }
+
+ if (x + width > screen_width)
+ {
+ width = screen_width - x;
+ }
+
+ if (y + height > screen_height)
+ {
+ height = screen_height - y;
+ }
+
+ if (width <= 0 || height <= 0)
+ return NULL;
+
+ dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
+ original_width, original_height);
+ src = gdk_pixbuf_get_from_drawable (NULL, root, NULL, x, y, 0, 0,
+ width, height);
+ gdk_pixbuf_copy_area (src, 0, 0, width, height, dest, 0, 0);
+
+ g_object_unref (G_OBJECT (src));
+
+ return dest;
+}
+
+static void
+shadow_paint(GtkWidget *widget, GdkRectangle *area, enum side shadow)
+{
+ GtkMenu *menu = GTK_MENU (widget);
+ GtkMenuPrivate *private = gtk_menu_get_private (menu);
+ gint width, height;
+ GdkGC *gc = widget->style->black_gc;
+
+ switch (shadow)
+ {
+ case EAST_SIDE:
+ if (private->east != NULL)
+ {
+ if (area)
+ gdk_gc_set_clip_rectangle (gc, area);
+
+ width = gdk_pixbuf_get_width (private->east);
+ height = gdk_pixbuf_get_height (private->east);
+
+ gdk_draw_pixbuf (private->east_shadow, gc, private->east, 0, 0, 0, 0,
+ width, height, GDK_RGB_DITHER_NONE, 0, 0);
+
+ if (area)
+ gdk_gc_set_clip_rectangle (gc, NULL);
+ }
+ break;
+ case SOUTH_SIDE:
+ if (private->south != NULL)
+ {
+ if (area)
+ gdk_gc_set_clip_rectangle (gc, area);
+
+ width = gdk_pixbuf_get_width (private->south);
+ height = gdk_pixbuf_get_height (private->south);
+
+ gdk_draw_pixbuf (private->south_shadow, gc, private->south, 0, 0, 0, 0,
+ width, height, GDK_RGB_DITHER_NONE, 0, 0);
+
+ if (area)
+ gdk_gc_set_clip_rectangle (gc, NULL);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+pixbuf_add_shadow (GdkPixbuf *pb,
+ enum side shadow)
+{
+ gint width, rowstride, height;
+ gint 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 EAST_SIDE:
+ if (height > 5)
+ {
+ for (i = 0; i < width; i++)
+ {
+ gint j, k;
+
+ p = pixels + (i * rowstride);
+ for (j = 0, k = 0; j < 3 * width; j += 3, k++)
+ {
+ p[j] = (guchar) (p[j] * top_right_corner [i * width + k]);
+ p[j + 1] = (guchar) (p[j + 1] * top_right_corner [i * width + k]);
+ p[j + 2] = (guchar) (p[j + 2] * top_right_corner [i * width + k]);
+ }
+ }
+
+ i = 5;
+ }
+ else
+ {
+ i = 0;
+ }
+
+ for (;i < height; i++)
+ {
+ gint j, k;
+
+ p = pixels + (i * rowstride);
+ for (j = 0, k = 0; j < 3 * width; j += 3, k++)
+ {
+ p[j] = (guchar) (p[j] * shadow_strip_l[width - 1 - k]);
+ p[j + 1] = (guchar) (p[j + 1] * shadow_strip_l[width - 1 - k]);
+ p[j + 2] = (guchar) (p[j + 2] * shadow_strip_l[width - 1 - k]);
+ }
+ }
+ break;
+
+ case SOUTH_SIDE:
+ for (i = 0; i < height; i++)
+ {
+ gint j, k;
+
+ p = pixels + (i * rowstride);
+ for (j = 0, k = 0; j < 3 * height; j += 3, k++)
+ {
+
+ p[j] = (guchar) (p[j] * bottom_left_corner[i * height + k]);
+ p[j + 1] = (guchar) (p[j + 1] * bottom_left_corner[i * height + k]);
+ p[j + 2] = (guchar) (p[j + 2] * bottom_left_corner[i * height + k]);
+ }
+
+ p = pixels + (i * rowstride) + 3 * height;
+ for (j = 0, k = 0; j < (width * 3) - (6 * height); j += 3, k++)
+ {
+ p[j] = (guchar) (p[j] * bottom_right_corner [i * height]);
+ p[j + 1] = (guchar) (p[j + 1] * bottom_right_corner [i * height]);
+ p[j + 2] = (guchar) (p[j + 2] * bottom_right_corner [i * height]);
+ }
+
+ p = pixels + (i * rowstride) + ((width * 3) - (3 * height));
+ for (j = 0, k = 0; j < 3 * height; j += 3, k++)
+ {
+ p[j] = (guchar) (p[j] * bottom_right_corner[i * height + k]);
+ p[j + 1] = (guchar) (p[j + 1] * bottom_right_corner[i * height + k]);
+ p[j + 2] = (guchar) (p[j + 2] * bottom_right_corner[i * height + k]);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static gboolean
+map_shadow_windows (gpointer data)
+{
+ GtkMenu *menu = GTK_MENU (data);
+ GtkMenuPrivate *private = gtk_menu_get_private (menu);
+ GtkWidget *widget = GTK_WIDGET (data);
+ GdkPixbuf *pixbuf;
+
+ pixbuf = get_pixbuf (menu,
+ private->x + widget->allocation.width, private->y,
+ 5, widget->allocation.height);
+ if (pixbuf != NULL)
+ {
+ pixbuf_add_shadow (pixbuf, EAST_SIDE);
+ if (private->east != NULL)
+ {
+ g_object_unref (G_OBJECT (private->east));
+ }
+ private->east = pixbuf;
+ }
+
+ pixbuf = get_pixbuf (menu,
+ private->x, private->y + widget->allocation.height,
+ widget->allocation.width + 5, 5);
+ if (pixbuf != NULL)
+ {
+ pixbuf_add_shadow (pixbuf, SOUTH_SIDE);
+ if (private->south != NULL)
+ {
+ g_object_unref (G_OBJECT (private->south));
+ }
+ private->south = pixbuf;
+ }
+
+ gdk_window_move_resize (private->east_shadow,
+ private->x + widget->allocation.width, private->y,
+ 5, widget->allocation.height);
+
+ gdk_window_move_resize (private->south_shadow,
+ private->x, private->y + widget->allocation.height,
+ widget->allocation.width + 5, 5);
+
+ gdk_window_show (private->east_shadow);
+ gdk_window_show (private->south_shadow);
+
+ shadow_paint(widget, NULL, EAST_SIDE);
+ shadow_paint(widget, NULL, SOUTH_SIDE);
+
+ private->timeout_id = 0;
+ return FALSE;
+}
+
+static void
+shadow_add_timeout(GtkWidget *widget)
+{
+ GtkMenuPrivate *private = gtk_menu_get_private (GTK_MENU (widget));
+ gboolean menu_shadow;
+ gint shadow_delay;
+
+ if (private->have_position)
+ {
+ g_object_get (G_OBJECT (gtk_widget_get_settings (widget)),
+ "gtk-menu-drop-shadow", &menu_shadow, NULL);
+
+ if (menu_shadow)
+ {
+ if (private->timeout_id > 0)
+ {
+ g_source_remove (private->timeout_id);
+ }
+
+
+ g_object_get (G_OBJECT (gtk_widget_get_settings (widget)),
+ "gtk-menu-shadow-delay", &shadow_delay,
+ NULL);
+
+ private->timeout_id = g_timeout_add (shadow_delay, map_shadow_windows, widget);
+ }
+ }
+}
+
+static void
+shadow_remove_timeout (GtkWidget *widget)
+{
+ GtkMenu *menu = GTK_MENU (widget);
+ GtkMenuPrivate *private = gtk_menu_get_private (menu);
+
+ if (private->timeout_id > 0)
+ {
+ g_source_remove (private->timeout_id);
+ private->timeout_id = 0;
+ }
+ else
+ {
+ if (private->east_shadow)
+ gdk_window_hide (private->east_shadow);
+
+ if (private->south_shadow)
+ gdk_window_hide (private->south_shadow);
+
+ if (private->east)
+ {
+ g_object_unref (G_OBJECT (private->east));
+ private->east = NULL;
+ }
+
+ if (private->south)
+ {
+ g_object_unref (G_OBJECT (private->south));
+ private->south = NULL;
+ }
+ }
+}
+
static void
gtk_menu_class_init (GtkMenuClass *class)
{
@@ -397,6 +767,20 @@
DEFAULT_POPDOWN_DELAY,
G_PARAM_READWRITE));
+ gtk_settings_install_property (g_param_spec_boolean ("gtk-menu-drop-shadow",
+ _("Display menu drop-shadow"),
+ _("Whether menu drop-shadow should be displayed"),
+ TRUE,
+ G_PARAM_READWRITE));
+
+ gtk_settings_install_property (g_param_spec_int ("gtk-menu-shadow-delay",
+ _("Delay before drop-shadow appear"),
+ _("Minimum time before drop-shadow appear under the menu"),
+ 0,
+ G_MAXINT,
+ DEFAULT_SHADOW_DELAY,
+ G_PARAM_READWRITE));
+
}
@@ -488,6 +872,8 @@
static void
gtk_menu_init (GtkMenu *menu)
{
+ GtkMenuPrivate *private = gtk_menu_get_private (menu);
+
menu->parent_menu_item = NULL;
menu->old_active_menu_item = NULL;
menu->accel_group = NULL;
@@ -532,6 +918,14 @@
menu->upper_arrow_prelight = FALSE;
menu->lower_arrow_prelight = FALSE;
+ private->east_shadow = NULL;
+ private->south_shadow = NULL;
+
+ private->east = NULL;
+ private->south = NULL;
+
+ private->timeout_id = 0;
+
MENU_NEEDS_RESIZE (menu) = TRUE;
}
@@ -594,6 +988,7 @@
menu_change_screen (GtkMenu *menu,
GdkScreen *new_screen)
{
+ shadow_remove_timeout(GTK_WIDGET(menu));
if (menu->torn_off)
{
gtk_window_set_screen (GTK_WINDOW (menu->tearoff_window), new_screen);
@@ -994,6 +1389,7 @@
if (xgrab_shell == widget)
popup_grab_on_window (widget->window, activate_time); /* Should always succeed */
+ shadow_add_timeout(GTK_WIDGET (menu));
gtk_grab_add (GTK_WIDGET (menu));
}
@@ -1004,7 +1400,7 @@
GtkMenuShell *menu_shell;
g_return_if_fail (GTK_IS_MENU (menu));
-
+
menu_shell = GTK_MENU_SHELL (menu);
private = gtk_menu_get_private (menu);
@@ -1068,6 +1464,7 @@
menu_shell->have_xgrab = FALSE;
gtk_grab_remove (GTK_WIDGET (menu));
+ shadow_remove_timeout(GTK_WIDGET (menu));
menu_grab_transfer_window_destroy (menu);
}
@@ -1473,10 +1870,16 @@
if (GTK_WIDGET_REALIZED (widget))
{
GtkMenu *menu = GTK_MENU (widget);
+ GtkMenuPrivate *private;
+ private = gtk_menu_get_private (menu);
+
gtk_style_set_background (widget->style, menu->bin_window, GTK_STATE_NORMAL);
gtk_style_set_background (widget->style, menu->view_window, GTK_STATE_NORMAL);
gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+
+ gdk_window_set_back_pixmap (private->east_shadow, NULL, FALSE);
+ gdk_window_set_back_pixmap (private->south_shadow, NULL, FALSE);
}
}
@@ -1487,12 +1890,14 @@
gint attributes_mask;
gint border_width;
GtkMenu *menu;
+ GtkMenuPrivate *private;
GtkWidget *child;
GList *children;
-
+
g_return_if_fail (GTK_IS_MENU (widget));
menu = GTK_MENU (widget);
+ private = gtk_menu_get_private (menu);
GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
@@ -1558,6 +1963,25 @@
gdk_window_show (menu->bin_window);
gdk_window_show (menu->view_window);
+
+ /* Drop shadow */
+
+ attributes.window_type = GDK_WINDOW_TEMP;
+ attributes.override_redirect = TRUE;
+
+ attributes_mask = GDK_WA_NOREDIR | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+ /* East drop shadow */
+ private->east_shadow = gdk_window_new (gtk_widget_get_root_window (widget),
+ &attributes, attributes_mask);
+ gdk_window_set_user_data (private->east_shadow, menu);
+ gdk_window_set_back_pixmap (private->east_shadow, NULL, FALSE);
+
+ /* South drop shadow */
+ private->south_shadow = gdk_window_new (gtk_widget_get_root_window (widget),
+ &attributes, attributes_mask);
+ gdk_window_set_user_data (private->south_shadow, menu);
+ gdk_window_set_back_pixmap (private->south_shadow, NULL, FALSE);
}
static gboolean
@@ -1620,10 +2044,12 @@
gtk_menu_unrealize (GtkWidget *widget)
{
GtkMenu *menu;
+ GtkMenuPrivate *private;
g_return_if_fail (GTK_IS_MENU (widget));
menu = GTK_MENU (widget);
+ private = gtk_menu_get_private (menu);
menu_grab_transfer_window_destroy (menu);
@@ -1635,6 +2061,15 @@
gdk_window_destroy (menu->bin_window);
menu->bin_window = NULL;
+ /* Shadows */
+ gdk_window_set_user_data (private->east_shadow, NULL);
+ gdk_window_destroy (private->east_shadow);
+ private->east_shadow = NULL;
+
+ gdk_window_set_user_data (private->south_shadow, NULL);
+ gdk_window_destroy (private->south_shadow);
+ private->south_shadow = NULL;
+
(* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
}
@@ -1753,8 +2188,15 @@
y,
width,
height);
- }
+ if (GTK_WIDGET_MAPPED (widget))
+ {
+ /* Remap the shadows as the menu size has changed */
+ shadow_remove_timeout(widget);
+ shadow_add_timeout(widget);
+ }
+ }
+
if (menu_shell->children)
{
child_allocation.x = 0;
@@ -1908,7 +2350,16 @@
MENU_SCROLL_ARROW_HEIGHT - 2 * border_y - 2,
MENU_SCROLL_ARROW_HEIGHT - 2 * border_y - 2);
}
- }
+ }
+ else
+ {
+ GtkMenuPrivate *private = gtk_menu_get_private (menu);
+
+ if (event->window == private->east_shadow)
+ shadow_paint(widget, &event->area, EAST_SIDE);
+ else if (event->window == private->south_shadow)
+ shadow_paint(widget, &event->area, SOUTH_SIDE);
+ }
}
static gboolean
Attachment:
signature.asc
Description: This is a digitally signed message part