Workaround for a gdk bug which dies with BadAlloc if you try to allocate

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.



svn path=/trunk/; revision=3191
This commit is contained in:
Thomas Thurman 2007-04-12 03:48:50 +00:00 committed by Thomas James Alexander Thurman
parent 7626f74b85
commit 2034a309e5
2 changed files with 96 additions and 35 deletions

View File

@ -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> 2007-04-11 Elijah Newren <newren gmail com>
Advertise support of Above and Below operations (assuming the Advertise support of Above and Below operations (assuming the

View File

@ -33,6 +33,7 @@
#include "fixedtip.h" #include "fixedtip.h"
#include "theme.h" #include "theme.h"
#include "prefs.h" #include "prefs.h"
#include "errors.h"
#ifdef HAVE_SHAPE #ifdef HAVE_SHAPE
#include <X11/extensions/shape.h> #include <X11/extensions/shape.h>
@ -2174,6 +2175,11 @@ meta_frames_expose_event (GtkWidget *widget,
return TRUE; 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 static void
meta_frames_paint_to_drawable (MetaFrames *frames, meta_frames_paint_to_drawable (MetaFrames *frames,
MetaUIFrame *frame, MetaUIFrame *frame,
@ -2191,12 +2197,6 @@ meta_frames_paint_to_drawable (MetaFrames *frames,
MetaButtonState button_states[META_BUTTON_TYPE_LAST]; MetaButtonState button_states[META_BUTTON_TYPE_LAST];
Window grab_frame; Window grab_frame;
int i; int i;
int top, bottom, left, right;
GdkRegion *edges;
GdkRegion *tmp_region;
GdkRectangle area;
GdkRectangle *areas;
int n_areas;
MetaButtonLayout button_layout; MetaButtonLayout button_layout;
MetaGrabOp grab_op; MetaGrabOp grab_op;
@ -2307,15 +2307,32 @@ meta_frames_paint_to_drawable (MetaFrames *frames,
meta_frames_ensure_layout (frames, frame); meta_frames_ensure_layout (frames, frame);
meta_prefs_get_button_layout (&button_layout);
if (G_LIKELY (GDK_IS_WINDOW (drawable)))
{
/* A window; happens about 2/3 of the time */
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 */
meta_theme_get_frame_borders (meta_theme_get_current (), meta_theme_get_frame_borders (meta_theme_get_current (),
type, frame->text_height, flags, type, frame->text_height, flags,
&top, &bottom, &left, &right); &top, &bottom, &left, &right);
/* Repaint each side of the frame */ meta_core_get_screen_size (gdk_display,
frame->xwindow,
&screen_width, &screen_height);
edges = gdk_region_copy (region); edges = gdk_region_copy (region);
/* Punch out the client area */ /* Punch out the client area */
area.x = left; area.x = left;
area.y = top; area.y = top;
area.width = w; area.width = w;
@ -2325,13 +2342,31 @@ meta_frames_paint_to_drawable (MetaFrames *frames,
gdk_region_destroy (tmp_region); gdk_region_destroy (tmp_region);
/* Now draw remaining portion of region */ /* Now draw remaining portion of region */
gdk_region_get_rectangles (edges, &areas, &n_areas); gdk_region_get_rectangles (edges, &areas, &n_areas);
meta_prefs_get_button_layout (&button_layout);
for (i = 0; i < n_areas; i++) for (i = 0; i < n_areas; i++)
{ {
if (GDK_IS_WINDOW (drawable)) /* 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]); gdk_window_begin_paint_rect (drawable, &areas[i]);
meta_theme_draw_frame (meta_theme_get_current (), meta_theme_draw_frame (meta_theme_get_current (),
widget, widget,
drawable, drawable,
@ -2346,12 +2381,32 @@ meta_frames_paint_to_drawable (MetaFrames *frames,
button_states, button_states,
mini_icon, icon); mini_icon, icon);
if (GDK_IS_WINDOW (drawable))
gdk_window_end_paint (drawable); gdk_window_end_paint (drawable);
} }
gdk_region_destroy (edges);
g_free (areas); g_free (areas);
gdk_region_destroy (edges);
}
else
{
/* Not a window; happens about 1/3 of the time */
meta_theme_draw_frame (meta_theme_get_current (),
widget,
drawable,
NULL,
x_offset, y_offset,
type,
flags,
w, h,
frame->layout,
frame->text_height,
&button_layout,
button_states,
mini_icon, icon);
}
} }
static void static void