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