diff options
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | src/frames.c | 119 |
2 files changed, 93 insertions, 32 deletions
@@ -1,3 +1,9 @@ +2007-04-11 Thomas Thurman <thomas@thurman.org.uk> + + Workaround for a gdk bug which dies with BadAlloc if you try + to allocate an insanely huge rectangle for an insanely huge + window. Fixes #399529. + 2007-04-11 Elijah Newren <newren gmail com> Advertise support of Above and Below operations (assuming the diff --git a/src/frames.c b/src/frames.c index 71a906fe..977099e9 100644 --- a/src/frames.c +++ b/src/frames.c @@ -33,6 +33,7 @@ #include "fixedtip.h" #include "theme.h" #include "prefs.h" +#include "errors.h" #ifdef HAVE_SHAPE #include <X11/extensions/shape.h> @@ -2174,6 +2175,11 @@ meta_frames_expose_event (GtkWidget *widget, return TRUE; } +/* How far off the screen edge the window decorations should + * be drawn. Used only in meta_frames_paint_to_drawable, below. + */ +#define DECORATING_BORDER 100 + static void meta_frames_paint_to_drawable (MetaFrames *frames, MetaUIFrame *frame, @@ -2191,12 +2197,6 @@ meta_frames_paint_to_drawable (MetaFrames *frames, MetaButtonState button_states[META_BUTTON_TYPE_LAST]; Window grab_frame; int i; - int top, bottom, left, right; - GdkRegion *edges; - GdkRegion *tmp_region; - GdkRectangle area; - GdkRectangle *areas; - int n_areas; MetaButtonLayout button_layout; MetaGrabOp grab_op; @@ -2307,35 +2307,95 @@ meta_frames_paint_to_drawable (MetaFrames *frames, meta_frames_ensure_layout (frames, frame); - meta_theme_get_frame_borders (meta_theme_get_current (), - type, frame->text_height, flags, - &top, &bottom, &left, &right); + meta_prefs_get_button_layout (&button_layout); - /* Repaint each side of the frame */ - - edges = gdk_region_copy (region); + if (G_LIKELY (GDK_IS_WINDOW (drawable))) + { + /* A window; happens about 2/3 of the time */ - /* Punch out the client area */ - area.x = left; - area.y = top; - area.width = w; - area.height = h; - tmp_region = gdk_region_rectangle (&area); - gdk_region_subtract (edges, tmp_region); - gdk_region_destroy (tmp_region); + GdkRectangle area, *areas; + int n_areas; + int screen_width, screen_height; + GdkRegion *edges, *tmp_region; + int top, bottom, left, right; + + /* Repaint each side of the frame */ - /* Now draw remaining portion of region */ - gdk_region_get_rectangles (edges, &areas, &n_areas); + meta_theme_get_frame_borders (meta_theme_get_current (), + type, frame->text_height, flags, + &top, &bottom, &left, &right); - meta_prefs_get_button_layout (&button_layout); - for (i = 0; i < n_areas; i++) + meta_core_get_screen_size (gdk_display, + frame->xwindow, + &screen_width, &screen_height); + + edges = gdk_region_copy (region); + + /* Punch out the client area */ + + area.x = left; + area.y = top; + area.width = w; + area.height = h; + tmp_region = gdk_region_rectangle (&area); + gdk_region_subtract (edges, tmp_region); + gdk_region_destroy (tmp_region); + + /* Now draw remaining portion of region */ + + gdk_region_get_rectangles (edges, &areas, &n_areas); + + for (i = 0; i < n_areas; i++) + { + /* Bug 399529: clamp areas[i] so that it doesn't go too far + * off the edge of the screen. This works around a GDK bug + * which makes gdk_window_begin_paint_rect cause an X error + * if the window is insanely huge. If the client is a GDK program + * and does this, it will still probably cause an X error in that + * program, but the last thing we want is for Metacity to crash + * because it attempted to decorate the silly window. + */ + + areas[i].x = MAX (areas[i].x, -DECORATING_BORDER); + areas[i].y = MAX (areas[i].y, -DECORATING_BORDER); + if (areas[i].x+areas[i].width > screen_width + DECORATING_BORDER) + areas[i].width = MIN (0, screen_width - areas[i].x); + if (areas[i].y+areas[i].height > screen_height + DECORATING_BORDER) + areas[i].height = MIN (0, screen_height - areas[i].y); + + /* Okay, so let's start painting. */ + + gdk_window_begin_paint_rect (drawable, &areas[i]); + + meta_theme_draw_frame (meta_theme_get_current (), + widget, + drawable, + NULL, /* &areas[i], */ + x_offset, y_offset, + type, + flags, + w, h, + frame->layout, + frame->text_height, + &button_layout, + button_states, + mini_icon, icon); + + gdk_window_end_paint (drawable); + } + + g_free (areas); + gdk_region_destroy (edges); + + } + else { - if (GDK_IS_WINDOW (drawable)) - gdk_window_begin_paint_rect (drawable, &areas[i]); + /* Not a window; happens about 1/3 of the time */ + meta_theme_draw_frame (meta_theme_get_current (), widget, drawable, - NULL, /* &areas[i], */ + NULL, x_offset, y_offset, type, flags, @@ -2345,13 +2405,8 @@ meta_frames_paint_to_drawable (MetaFrames *frames, &button_layout, button_states, mini_icon, icon); - - if (GDK_IS_WINDOW (drawable)) - gdk_window_end_paint (drawable); } - gdk_region_destroy (edges); - g_free (areas); } static void |