- gamma_correct (f, color);
- return x_alloc_nearest_color_1 (FRAME_X_DISPLAY (f), cmap, color);
-}
-
-
-/* Allocate color PIXEL on frame F. PIXEL must already be allocated.
- It's necessary to do this instead of just using PIXEL directly to
- get color reference counts right. */
-
-unsigned long
-x_copy_color (f, pixel)
- struct frame *f;
- unsigned long pixel;
-{
- XColor color;
-
- color.pixel = pixel;
- BLOCK_INPUT;
- x_query_color (f, &color);
- XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
- UNBLOCK_INPUT;
-#ifdef DEBUG_X_COLORS
- register_color (pixel);
-#endif
- return color.pixel;
-}
-
-
-/* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
- It's necessary to do this instead of just using PIXEL directly to
- get color reference counts right. */
-
-unsigned long
-x_copy_dpy_color (dpy, cmap, pixel)
- Display *dpy;
- Colormap cmap;
- unsigned long pixel;
-{
- XColor color;
-
- color.pixel = pixel;
- BLOCK_INPUT;
- XQueryColor (dpy, cmap, &color);
- XAllocColor (dpy, cmap, &color);
- UNBLOCK_INPUT;
-#ifdef DEBUG_X_COLORS
- register_color (pixel);
-#endif
- return color.pixel;
-}
-
-
-/* Brightness beyond which a color won't have its highlight brightness
- boosted.
-
- Nominally, highlight colors for `3d' faces are calculated by
- brightening an object's color by a constant scale factor, but this
- doesn't yield good results for dark colors, so for colors who's
- brightness is less than this value (on a scale of 0-65535) have an
- use an additional additive factor.
-
- The value here is set so that the default menu-bar/mode-line color
- (grey75) will not have its highlights changed at all. */
-#define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000
-
-
-/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
- or DELTA. Try a color with RGB values multiplied by FACTOR first.
- If this produces the same color as PIXEL, try a color where all RGB
- values have DELTA added. Return the allocated color in *PIXEL.
- DISPLAY is the X display, CMAP is the colormap to operate on.
- Value is non-zero if successful. */
-
-static int
-x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
- struct frame *f;
- Display *display;
- Colormap cmap;
- unsigned long *pixel;
- double factor;
- int delta;
-{
- XColor color, new;
- long bright;
- int success_p;
-
- /* Get RGB color values. */
- color.pixel = *pixel;
- x_query_color (f, &color);
-
- /* Change RGB values by specified FACTOR. Avoid overflow! */
- xassert (factor >= 0);
- new.red = min (0xffff, factor * color.red);
- new.green = min (0xffff, factor * color.green);
- new.blue = min (0xffff, factor * color.blue);
-
- /* Calculate brightness of COLOR. */
- bright = (2 * color.red + 3 * color.green + color.blue) / 6;
-
- /* We only boost colors that are darker than
- HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
- if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
- /* Make an additive adjustment to NEW, because it's dark enough so
- that scaling by FACTOR alone isn't enough. */
- {
- /* How far below the limit this color is (0 - 1, 1 being darker). */
- double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
- /* The additive adjustment. */
- int min_delta = delta * dimness * factor / 2;
-
- if (factor < 1)
- {
- new.red = max (0, new.red - min_delta);
- new.green = max (0, new.green - min_delta);
- new.blue = max (0, new.blue - min_delta);
- }
- else
- {
- new.red = min (0xffff, min_delta + new.red);
- new.green = min (0xffff, min_delta + new.green);
- new.blue = min (0xffff, min_delta + new.blue);
- }
- }
-
- /* Try to allocate the color. */
- success_p = x_alloc_nearest_color (f, cmap, &new);
- if (success_p)
- {
- if (new.pixel == *pixel)
- {
- /* If we end up with the same color as before, try adding
- delta to the RGB values. */
- x_free_colors (f, &new.pixel, 1);
-
- new.red = min (0xffff, delta + color.red);
- new.green = min (0xffff, delta + color.green);
- new.blue = min (0xffff, delta + color.blue);
- success_p = x_alloc_nearest_color (f, cmap, &new);
- }
- else
- success_p = 1;
- *pixel = new.pixel;
- }
-
- return success_p;
-}
-
-
-/* Set up the foreground color for drawing relief lines of glyph
- string S. RELIEF is a pointer to a struct relief containing the GC
- with which lines will be drawn. Use a color that is FACTOR or
- DELTA lighter or darker than the relief's background which is found
- in S->f->output_data.x->relief_background. If such a color cannot
- be allocated, use DEFAULT_PIXEL, instead. */
-
-static void
-x_setup_relief_color (f, relief, factor, delta, default_pixel)
- struct frame *f;
- struct relief *relief;
- double factor;
- int delta;
- unsigned long default_pixel;
-{
- XGCValues xgcv;
- struct x_output *di = f->output_data.x;
- unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
- unsigned long pixel;
- unsigned long background = di->relief_background;
- Colormap cmap = FRAME_X_COLORMAP (f);
- struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
- Display *dpy = FRAME_X_DISPLAY (f);
-
- xgcv.graphics_exposures = False;
- xgcv.line_width = 1;
-
- /* Free previously allocated color. The color cell will be reused
- when it has been freed as many times as it was allocated, so this
- doesn't affect faces using the same colors. */
- if (relief->gc
- && relief->allocated_p)
- {
- x_free_colors (f, &relief->pixel, 1);
- relief->allocated_p = 0;
- }
-
- /* Allocate new color. */
- xgcv.foreground = default_pixel;
- pixel = background;
- if (dpyinfo->n_planes != 1
- && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
- {
- relief->allocated_p = 1;
- xgcv.foreground = relief->pixel = pixel;
- }
-
- if (relief->gc == 0)
- {
- xgcv.stipple = dpyinfo->gray;
- mask |= GCStipple;
- relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
- }
- else
- XChangeGC (dpy, relief->gc, mask, &xgcv);
-}
-
-
-/* Set up colors for the relief lines around glyph string S. */
-
-static void
-x_setup_relief_colors (s)
- struct glyph_string *s;
-{
- struct x_output *di = s->f->output_data.x;
- unsigned long color;
-
- if (s->face->use_box_color_for_shadows_p)
- color = s->face->box_color;
- else if (s->first_glyph->type == IMAGE_GLYPH
- && s->img->pixmap
- && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
- color = IMAGE_BACKGROUND (s->img, s->f, 0);
- else
- {
- XGCValues xgcv;
-
- /* Get the background color of the face. */
- XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
- color = xgcv.background;
- }
-
- if (di->white_relief.gc == 0
- || color != di->relief_background)
- {
- di->relief_background = color;
- x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
- WHITE_PIX_DEFAULT (s->f));
- x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
- BLACK_PIX_DEFAULT (s->f));
- }
-}
-
-
-/* Draw a relief on frame F inside the rectangle given by LEFT_X,
- TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
- to draw, it must be >= 0. RAISED_P non-zero means draw a raised
- relief. LEFT_P non-zero means draw a relief on the left side of
- the rectangle. RIGHT_P non-zero means draw a relief on the right
- side of the rectangle. CLIP_RECT is the clipping rectangle to use
- when drawing. */
-
-static void
-x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
- raised_p, left_p, right_p, clip_rect)
- struct frame *f;
- int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
- XRectangle *clip_rect;
-{
- Display *dpy = FRAME_X_DISPLAY (f);
- Window window = FRAME_X_WINDOW (f);
- int i;
- GC gc;
-
- if (raised_p)
- gc = f->output_data.x->white_relief.gc;
- else
- gc = f->output_data.x->black_relief.gc;
- XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
-
- /* Top. */
- for (i = 0; i < width; ++i)
- XDrawLine (dpy, window, gc,
- left_x + i * left_p, top_y + i,
- right_x + 1 - i * right_p, top_y + i);
-
- /* Left. */
- if (left_p)
- for (i = 0; i < width; ++i)
- XDrawLine (dpy, window, gc,
- left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
-
- XSetClipMask (dpy, gc, None);
- if (raised_p)
- gc = f->output_data.x->black_relief.gc;
- else
- gc = f->output_data.x->white_relief.gc;
- XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
-
- /* Bottom. */
- for (i = 0; i < width; ++i)
- XDrawLine (dpy, window, gc,
- left_x + i * left_p, bottom_y - i,
- right_x + 1 - i * right_p, bottom_y - i);
-
- /* Right. */
- if (right_p)
- for (i = 0; i < width; ++i)
- XDrawLine (dpy, window, gc,
- right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
-
- XSetClipMask (dpy, gc, None);
-}
-
-
-/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
- RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
- draw, it must be >= 0. LEFT_P non-zero means draw a line on the
- left side of the rectangle. RIGHT_P non-zero means draw a line
- on the right side of the rectangle. CLIP_RECT is the clipping
- rectangle to use when drawing. */
-
-static void
-x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
- left_p, right_p, clip_rect)
- struct glyph_string *s;
- int left_x, top_y, right_x, bottom_y, left_p, right_p;
- XRectangle *clip_rect;
-{
- XGCValues xgcv;
-
- XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
- XSetForeground (s->display, s->gc, s->face->box_color);
- XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
-
- /* Top. */
- XFillRectangle (s->display, s->window, s->gc,
- left_x, top_y, right_x - left_x + 1, width);
-
- /* Left. */
- if (left_p)
- XFillRectangle (s->display, s->window, s->gc,
- left_x, top_y, width, bottom_y - top_y + 1);
-
- /* Bottom. */
- XFillRectangle (s->display, s->window, s->gc,
- left_x, bottom_y - width + 1, right_x - left_x + 1, width);
-
- /* Right. */
- if (right_p)
- XFillRectangle (s->display, s->window, s->gc,
- right_x - width + 1, top_y, width, bottom_y - top_y + 1);
-
- XSetForeground (s->display, s->gc, xgcv.foreground);
- XSetClipMask (s->display, s->gc, None);
-}
-
-
-/* Draw a box around glyph string S. */
-
-static void
-x_draw_glyph_string_box (s)
- struct glyph_string *s;
-{
- int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
- int left_p, right_p;
- struct glyph *last_glyph;
- XRectangle clip_rect;
-
- last_x = window_box_right (s->w, s->area);
- if (s->row->full_width_p
- && !s->w->pseudo_window_p)
- {
- last_x += FRAME_X_RIGHT_FRINGE_WIDTH (s->f);
- if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
- last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
- }
-
- /* The glyph that may have a right box line. */
- last_glyph = (s->cmp || s->img
- ? s->first_glyph
- : s->first_glyph + s->nchars - 1);
-
- width = abs (s->face->box_line_width);
- raised_p = s->face->box == FACE_RAISED_BOX;
- left_x = s->x;
- right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
- ? last_x - 1
- : min (last_x, s->x + s->background_width) - 1);
- top_y = s->y;
- bottom_y = top_y + s->height - 1;
-
- left_p = (s->first_glyph->left_box_line_p
- || (s->hl == DRAW_MOUSE_FACE
- && (s->prev == NULL
- || s->prev->hl != s->hl)));
- right_p = (last_glyph->right_box_line_p
- || (s->hl == DRAW_MOUSE_FACE
- && (s->next == NULL
- || s->next->hl != s->hl)));
-
- x_get_glyph_string_clip_rect (s, &clip_rect);
-
- if (s->face->box == FACE_SIMPLE_BOX)
- x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
- left_p, right_p, &clip_rect);
- else
- {
- x_setup_relief_colors (s);
- x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
- width, raised_p, left_p, right_p, &clip_rect);
- }
-}
-
-
-/* Draw foreground of image glyph string S. */
-
-static void
-x_draw_image_foreground (s)
- struct glyph_string *s;
-{
- int x;
- int y = s->ybase - image_ascent (s->img, s->face);
-
- /* If first glyph of S has a left box line, start drawing it to the
- right of that line. */
- if (s->face->box != FACE_NO_BOX
- && s->first_glyph->left_box_line_p)
- x = s->x + abs (s->face->box_line_width);
- else
- x = s->x;
-
- /* If there is a margin around the image, adjust x- and y-position
- by that margin. */
- x += s->img->hmargin;
- y += s->img->vmargin;
-
- if (s->img->pixmap)
- {
- if (s->img->mask)
- {
- /* We can't set both a clip mask and use XSetClipRectangles
- because the latter also sets a clip mask. We also can't
- trust on the shape extension to be available
- (XShapeCombineRegion). So, compute the rectangle to draw
- manually. */
- unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
- | GCFunction);
- XGCValues xgcv;
- XRectangle clip_rect, image_rect, r;
-
- xgcv.clip_mask = s->img->mask;
- xgcv.clip_x_origin = x;
- xgcv.clip_y_origin = y;
- xgcv.function = GXcopy;
- XChangeGC (s->display, s->gc, mask, &xgcv);
-
- x_get_glyph_string_clip_rect (s, &clip_rect);
- image_rect.x = x;
- image_rect.y = y;
- image_rect.width = s->img->width;
- image_rect.height = s->img->height;
- if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
- XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
- r.x - x, r.y - y, r.width, r.height, r.x, r.y);
- }
- else
- {
- XRectangle clip_rect, image_rect, r;
-
- x_get_glyph_string_clip_rect (s, &clip_rect);
- image_rect.x = x;
- image_rect.y = y;
- image_rect.width = s->img->width;
- image_rect.height = s->img->height;
- if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
- XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
- r.x - x, r.y - y, r.width, r.height, r.x, r.y);
-
- /* When the image has a mask, we can expect that at
- least part of a mouse highlight or a block cursor will
- be visible. If the image doesn't have a mask, make
- a block cursor visible by drawing a rectangle around
- the image. I believe it's looking better if we do
- nothing here for mouse-face. */
- if (s->hl == DRAW_CURSOR)
- {
- int r = s->img->relief;
- if (r < 0) r = -r;
- XDrawRectangle (s->display, s->window, s->gc, x - r, y - r,
- s->img->width + r*2 - 1, s->img->height + r*2 - 1);
- }
- }
- }
- else
- /* Draw a rectangle if image could not be loaded. */
- XDrawRectangle (s->display, s->window, s->gc, x, y,
- s->img->width - 1, s->img->height - 1);
-}
-
-
-/* Draw a relief around the image glyph string S. */
-
-static void
-x_draw_image_relief (s)
- struct glyph_string *s;
-{
- int x0, y0, x1, y1, thick, raised_p;
- XRectangle r;
- int x;
- int y = s->ybase - image_ascent (s->img, s->face);
-
- /* If first glyph of S has a left box line, start drawing it to the
- right of that line. */
- if (s->face->box != FACE_NO_BOX
- && s->first_glyph->left_box_line_p)
- x = s->x + abs (s->face->box_line_width);
- else
- x = s->x;
-
- /* If there is a margin around the image, adjust x- and y-position
- by that margin. */
- x += s->img->hmargin;
- y += s->img->vmargin;
-
- if (s->hl == DRAW_IMAGE_SUNKEN
- || s->hl == DRAW_IMAGE_RAISED)
- {
- thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
- raised_p = s->hl == DRAW_IMAGE_RAISED;
- }
- else
- {
- thick = abs (s->img->relief);
- raised_p = s->img->relief > 0;
- }
-
- x0 = x - thick;
- y0 = y - thick;
- x1 = x + s->img->width + thick - 1;
- y1 = y + s->img->height + thick - 1;
-
- x_setup_relief_colors (s);
- x_get_glyph_string_clip_rect (s, &r);
- x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
-}
-
-
-/* Draw the foreground of image glyph string S to PIXMAP. */
-
-static void
-x_draw_image_foreground_1 (s, pixmap)
- struct glyph_string *s;
- Pixmap pixmap;
-{
- int x;
- int y = s->ybase - s->y - image_ascent (s->img, s->face);
-
- /* If first glyph of S has a left box line, start drawing it to the
- right of that line. */
- if (s->face->box != FACE_NO_BOX
- && s->first_glyph->left_box_line_p)
- x = abs (s->face->box_line_width);
- else
- x = 0;
-
- /* If there is a margin around the image, adjust x- and y-position
- by that margin. */
- x += s->img->hmargin;
- y += s->img->vmargin;
-
- if (s->img->pixmap)
- {
- if (s->img->mask)
- {
- /* We can't set both a clip mask and use XSetClipRectangles
- because the latter also sets a clip mask. We also can't
- trust on the shape extension to be available
- (XShapeCombineRegion). So, compute the rectangle to draw
- manually. */
- unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
- | GCFunction);
- XGCValues xgcv;
-
- xgcv.clip_mask = s->img->mask;
- xgcv.clip_x_origin = x;
- xgcv.clip_y_origin = y;
- xgcv.function = GXcopy;
- XChangeGC (s->display, s->gc, mask, &xgcv);
-
- XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
- 0, 0, s->img->width, s->img->height, x, y);
- XSetClipMask (s->display, s->gc, None);
- }
- else
- {
- XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
- 0, 0, s->img->width, s->img->height, x, y);
-
- /* When the image has a mask, we can expect that at
- least part of a mouse highlight or a block cursor will
- be visible. If the image doesn't have a mask, make
- a block cursor visible by drawing a rectangle around
- the image. I believe it's looking better if we do
- nothing here for mouse-face. */
- if (s->hl == DRAW_CURSOR)
- {
- int r = s->img->relief;
- if (r < 0) r = -r;
- XDrawRectangle (s->display, s->window, s->gc, x - r, y - r,
- s->img->width + r*2 - 1, s->img->height + r*2 - 1);
- }
- }
- }
- else
- /* Draw a rectangle if image could not be loaded. */
- XDrawRectangle (s->display, pixmap, s->gc, x, y,
- s->img->width - 1, s->img->height - 1);
-}
-
-
-/* Draw part of the background of glyph string S. X, Y, W, and H
- give the rectangle to draw. */
-
-static void
-x_draw_glyph_string_bg_rect (s, x, y, w, h)
- struct glyph_string *s;
- int x, y, w, h;
-{
- if (s->stippled_p)
- {
- /* Fill background with a stipple pattern. */
- XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
- XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
- XSetFillStyle (s->display, s->gc, FillSolid);
- }
- else
- x_clear_glyph_string_rect (s, x, y, w, h);
-}
-
-
-/* Draw image glyph string S.
-
- s->y
- s->x +-------------------------
- | s->face->box
- |
- | +-------------------------
- | | s->img->margin
- | |
- | | +-------------------
- | | | the image
-
- */
-
-static void
-x_draw_image_glyph_string (s)
- struct glyph_string *s;
-{
- int x, y;
- int box_line_hwidth = abs (s->face->box_line_width);
- int box_line_vwidth = max (s->face->box_line_width, 0);
- int height;
- Pixmap pixmap = None;
-
- height = s->height - 2 * box_line_vwidth;
-
- /* Fill background with face under the image. Do it only if row is
- taller than image or if image has a clip mask to reduce
- flickering. */
- s->stippled_p = s->face->stipple != 0;
- if (height > s->img->height
- || s->img->hmargin
- || s->img->vmargin
- || s->img->mask
- || s->img->pixmap == 0
- || s->width != s->background_width)
- {
- if (box_line_hwidth && s->first_glyph->left_box_line_p)
- x = s->x + box_line_hwidth;
- else
- x = s->x;
-
- y = s->y + box_line_vwidth;
-
- if (s->img->mask)
- {
- /* Create a pixmap as large as the glyph string. Fill it
- with the background color. Copy the image to it, using
- its mask. Copy the temporary pixmap to the display. */
- Screen *screen = FRAME_X_SCREEN (s->f);
- int depth = DefaultDepthOfScreen (screen);
-
- /* Create a pixmap as large as the glyph string. */
- pixmap = XCreatePixmap (s->display, s->window,
- s->background_width,
- s->height, depth);
-
- /* Don't clip in the following because we're working on the
- pixmap. */
- XSetClipMask (s->display, s->gc, None);
-
- /* Fill the pixmap with the background color/stipple. */
- if (s->stippled_p)
- {
- /* Fill background with a stipple pattern. */
- XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
- XFillRectangle (s->display, pixmap, s->gc,
- 0, 0, s->background_width, s->height);
- XSetFillStyle (s->display, s->gc, FillSolid);
- }
- else
- {
- XGCValues xgcv;
- XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
- &xgcv);
- XSetForeground (s->display, s->gc, xgcv.background);
- XFillRectangle (s->display, pixmap, s->gc,
- 0, 0, s->background_width, s->height);
- XSetForeground (s->display, s->gc, xgcv.foreground);
- }
- }
- else
- x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
-
- s->background_filled_p = 1;
- }
-
- /* Draw the foreground. */
- if (pixmap != None)
- {
- x_draw_image_foreground_1 (s, pixmap);
- x_set_glyph_string_clipping (s);
- XCopyArea (s->display, pixmap, s->window, s->gc,
- 0, 0, s->background_width, s->height, s->x, s->y);
- XFreePixmap (s->display, pixmap);
- }
- else
- x_draw_image_foreground (s);
-
- /* If we must draw a relief around the image, do it. */
- if (s->img->relief
- || s->hl == DRAW_IMAGE_RAISED
- || s->hl == DRAW_IMAGE_SUNKEN)
- x_draw_image_relief (s);
-}
-
-
-/* Draw stretch glyph string S. */
-
-static void
-x_draw_stretch_glyph_string (s)
- struct glyph_string *s;
-{
- xassert (s->first_glyph->type == STRETCH_GLYPH);
- s->stippled_p = s->face->stipple != 0;
-
- if (s->hl == DRAW_CURSOR
- && !x_stretch_cursor_p)
- {
- /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
- as wide as the stretch glyph. */
- int width = min (CANON_X_UNIT (s->f), s->background_width);
-
- /* Draw cursor. */
- x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
-
- /* Clear rest using the GC of the original non-cursor face. */
- if (width < s->background_width)
- {
- int x = s->x + width, y = s->y;
- int w = s->background_width - width, h = s->height;
- XRectangle r;
- GC gc;
-
- if (s->row->mouse_face_p
- && cursor_in_mouse_face_p (s->w))
- {
- x_set_mouse_face_gc (s);
- gc = s->gc;
- }
- else
- gc = s->face->gc;
-
- x_get_glyph_string_clip_rect (s, &r);
- XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
-
- if (s->face->stipple)
- {
- /* Fill background with a stipple pattern. */
- XSetFillStyle (s->display, gc, FillOpaqueStippled);
- XFillRectangle (s->display, s->window, gc, x, y, w, h);
- XSetFillStyle (s->display, gc, FillSolid);
- }
- else
- {
- XGCValues xgcv;
- XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
- XSetForeground (s->display, gc, xgcv.background);
- XFillRectangle (s->display, s->window, gc, x, y, w, h);
- XSetForeground (s->display, gc, xgcv.foreground);
- }
- }
- }
- else if (!s->background_filled_p)
- x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
- s->height);
-
- s->background_filled_p = 1;
-}
-
-
-/* Draw glyph string S. */
-
-static void
-x_draw_glyph_string (s)
- struct glyph_string *s;
-{
- int relief_drawn_p = 0;
-
- /* If S draws into the background of its successor, draw the
- background of the successor first so that S can draw into it.
- This makes S->next use XDrawString instead of XDrawImageString. */
- if (s->next && s->right_overhang && !s->for_overlaps_p)
- {
- xassert (s->next->img == NULL);
- x_set_glyph_string_gc (s->next);
- x_set_glyph_string_clipping (s->next);
- x_draw_glyph_string_background (s->next, 1);
- }
-
- /* Set up S->gc, set clipping and draw S. */
- x_set_glyph_string_gc (s);
-
- /* Draw relief (if any) in advance for char/composition so that the
- glyph string can be drawn over it. */
- if (!s->for_overlaps_p
- && s->face->box != FACE_NO_BOX
- && (s->first_glyph->type == CHAR_GLYPH
- || s->first_glyph->type == COMPOSITE_GLYPH))
-
- {
- x_set_glyph_string_clipping (s);
- x_draw_glyph_string_background (s, 1);
- x_draw_glyph_string_box (s);
- x_set_glyph_string_clipping (s);
- relief_drawn_p = 1;
- }
- else
- x_set_glyph_string_clipping (s);
-
- switch (s->first_glyph->type)
- {
- case IMAGE_GLYPH:
- x_draw_image_glyph_string (s);
- break;
-
- case STRETCH_GLYPH:
- x_draw_stretch_glyph_string (s);
- break;
-
- case CHAR_GLYPH:
- if (s->for_overlaps_p)
- s->background_filled_p = 1;
- else
- x_draw_glyph_string_background (s, 0);
- x_draw_glyph_string_foreground (s);
- break;
-
- case COMPOSITE_GLYPH:
- if (s->for_overlaps_p || s->gidx > 0)
- s->background_filled_p = 1;
- else
- x_draw_glyph_string_background (s, 1);
- x_draw_composite_glyph_string_foreground (s);
- break;
-
- default:
- abort ();
- }
-
- if (!s->for_overlaps_p)
- {
- /* Draw underline. */
- if (s->face->underline_p)
- {
- unsigned long tem, h;
- int y;
-
- /* Get the underline thickness. Default is 1 pixel. */
- if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
- h = 1;
-
- /* Get the underline position. This is the recommended
- vertical offset in pixels from the baseline to the top of
- the underline. This is a signed value according to the
- specs, and its default is
-
- ROUND ((maximum descent) / 2), with
- ROUND(x) = floor (x + 0.5) */
-
- if (x_use_underline_position_properties
- && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
- y = s->ybase + (long) tem;
- else if (s->face->font)
- y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
- else
- y = s->y + s->height - h;
-
- if (s->face->underline_defaulted_p)
- XFillRectangle (s->display, s->window, s->gc,
- s->x, y, s->width, h);
- else
- {
- XGCValues xgcv;
- XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
- XSetForeground (s->display, s->gc, s->face->underline_color);
- XFillRectangle (s->display, s->window, s->gc,
- s->x, y, s->width, h);
- XSetForeground (s->display, s->gc, xgcv.foreground);
- }
- }
-
- /* Draw overline. */
- if (s->face->overline_p)
- {
- unsigned long dy = 0, h = 1;
-
- if (s->face->overline_color_defaulted_p)
- XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
- s->width, h);
- else
- {
- XGCValues xgcv;
- XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
- XSetForeground (s->display, s->gc, s->face->overline_color);
- XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
- s->width, h);
- XSetForeground (s->display, s->gc, xgcv.foreground);
- }
- }
-
- /* Draw strike-through. */
- if (s->face->strike_through_p)
- {
- unsigned long h = 1;
- unsigned long dy = (s->height - h) / 2;
-
- if (s->face->strike_through_color_defaulted_p)
- XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
- s->width, h);
- else
- {
- XGCValues xgcv;
- XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
- XSetForeground (s->display, s->gc, s->face->strike_through_color);
- XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
- s->width, h);
- XSetForeground (s->display, s->gc, xgcv.foreground);
- }
- }
-
- /* Draw relief if not yet drawn. */
- if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
- x_draw_glyph_string_box (s);
- }
-
- /* Reset clipping. */
- XSetClipMask (s->display, s->gc, None);
-}
-
-
-static int x_fill_composite_glyph_string P_ ((struct glyph_string *,
- struct face **, int));
-
-
-/* Fill glyph string S with composition components specified by S->cmp.
-
- FACES is an array of faces for all components of this composition.
- S->gidx is the index of the first component for S.
- OVERLAPS_P non-zero means S should draw the foreground only, and
- use its physical height for clipping.
-
- Value is the index of a component not in S. */
-
-static int
-x_fill_composite_glyph_string (s, faces, overlaps_p)
- struct glyph_string *s;
- struct face **faces;
- int overlaps_p;
-{
- int i;
-
- xassert (s);
-
- s->for_overlaps_p = overlaps_p;
-
- s->face = faces[s->gidx];
- s->font = s->face->font;
- s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
-
- /* For all glyphs of this composition, starting at the offset
- S->gidx, until we reach the end of the definition or encounter a
- glyph that requires the different face, add it to S. */
- ++s->nchars;
- for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
- ++s->nchars;
-
- /* All glyph strings for the same composition has the same width,
- i.e. the width set for the first component of the composition. */
-
- s->width = s->first_glyph->pixel_width;
-
- /* If the specified font could not be loaded, use the frame's
- default font, but record the fact that we couldn't load it in
- the glyph string so that we can draw rectangles for the
- characters of the glyph string. */
- if (s->font == NULL)
- {
- s->font_not_found_p = 1;
- s->font = FRAME_FONT (s->f);
- }
-
- /* Adjust base line for subscript/superscript text. */
- s->ybase += s->first_glyph->voffset;
-
- xassert (s->face && s->face->gc);
-
- /* This glyph string must always be drawn with 16-bit functions. */
- s->two_byte_p = 1;
-
- return s->gidx + s->nchars;
-}
-
-
-/* Fill glyph string S from a sequence of character glyphs.
-
- FACE_ID is the face id of the string. START is the index of the
- first glyph to consider, END is the index of the last + 1.
- OVERLAPS_P non-zero means S should draw the foreground only, and
- use its physical height for clipping.
-
- Value is the index of the first glyph not in S. */
-
-static int
-x_fill_glyph_string (s, face_id, start, end, overlaps_p)
- struct glyph_string *s;
- int face_id;
- int start, end, overlaps_p;
-{
- struct glyph *glyph, *last;
- int voffset;
- int glyph_not_available_p;
-
- xassert (s->f == XFRAME (s->w->frame));
- xassert (s->nchars == 0);
- xassert (start >= 0 && end > start);
-
- s->for_overlaps_p = overlaps_p,
- glyph = s->row->glyphs[s->area] + start;
- last = s->row->glyphs[s->area] + end;
- voffset = glyph->voffset;
-
- glyph_not_available_p = glyph->glyph_not_available_p;
-
- while (glyph < last
- && glyph->type == CHAR_GLYPH
- && glyph->voffset == voffset
- /* Same face id implies same font, nowadays. */
- && glyph->face_id == face_id
- && glyph->glyph_not_available_p == glyph_not_available_p)
- {
- int two_byte_p;
-
- s->face = x_get_glyph_face_and_encoding (s->f, glyph,
- s->char2b + s->nchars,
- &two_byte_p);
- s->two_byte_p = two_byte_p;
- ++s->nchars;
- xassert (s->nchars <= end - start);
- s->width += glyph->pixel_width;
- ++glyph;
- }
-
- s->font = s->face->font;
- s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
-
- /* If the specified font could not be loaded, use the frame's font,
- but record the fact that we couldn't load it in
- S->font_not_found_p so that we can draw rectangles for the
- characters of the glyph string. */
- if (s->font == NULL || glyph_not_available_p)
- {
- s->font_not_found_p = 1;
- s->font = FRAME_FONT (s->f);
- }
-
- /* Adjust base line for subscript/superscript text. */
- s->ybase += voffset;
-
- xassert (s->face && s->face->gc);
- return glyph - s->row->glyphs[s->area];
-}
-
-
-/* Fill glyph string S from image glyph S->first_glyph. */
-
-static void
-x_fill_image_glyph_string (s)
- struct glyph_string *s;
-{
- xassert (s->first_glyph->type == IMAGE_GLYPH);
- s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
- xassert (s->img);
- s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
- s->font = s->face->font;
- s->width = s->first_glyph->pixel_width;
-
- /* Adjust base line for subscript/superscript text. */
- s->ybase += s->first_glyph->voffset;
-}
-
-
-/* Fill glyph string S from a sequence of stretch glyphs.
-
- ROW is the glyph row in which the glyphs are found, AREA is the
- area within the row. START is the index of the first glyph to
- consider, END is the index of the last + 1.
-
- Value is the index of the first glyph not in S. */
-
-static int
-x_fill_stretch_glyph_string (s, row, area, start, end)
- struct glyph_string *s;
- struct glyph_row *row;
- enum glyph_row_area area;
- int start, end;
-{
- struct glyph *glyph, *last;
- int voffset, face_id;
-
- xassert (s->first_glyph->type == STRETCH_GLYPH);
-
- glyph = s->row->glyphs[s->area] + start;
- last = s->row->glyphs[s->area] + end;
- face_id = glyph->face_id;
- s->face = FACE_FROM_ID (s->f, face_id);
- s->font = s->face->font;
- s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
- s->width = glyph->pixel_width;
- voffset = glyph->voffset;
-
- for (++glyph;
- (glyph < last
- && glyph->type == STRETCH_GLYPH
- && glyph->voffset == voffset
- && glyph->face_id == face_id);
- ++glyph)
- s->width += glyph->pixel_width;
-
- /* Adjust base line for subscript/superscript text. */
- s->ybase += voffset;
-
- /* The case that face->gc == 0 is handled when drawing the glyph
- string by calling PREPARE_FACE_FOR_DISPLAY. */
- xassert (s->face);
- return glyph - s->row->glyphs[s->area];
-}
-
-
-/* Initialize glyph string S. CHAR2B is a suitably allocated vector
- of XChar2b structures for S; it can't be allocated in
- x_init_glyph_string because it must be allocated via `alloca'. W
- is the window on which S is drawn. ROW and AREA are the glyph row
- and area within the row from which S is constructed. START is the
- index of the first glyph structure covered by S. HL is a
- face-override for drawing S. */
-
-static void
-x_init_glyph_string (s, char2b, w, row, area, start, hl)
- struct glyph_string *s;
- XChar2b *char2b;
- struct window *w;
- struct glyph_row *row;
- enum glyph_row_area area;
- int start;
- enum draw_glyphs_face hl;
-{
- bzero (s, sizeof *s);
- s->w = w;
- s->f = XFRAME (w->frame);
- s->display = FRAME_X_DISPLAY (s->f);
- s->window = FRAME_X_WINDOW (s->f);
- s->char2b = char2b;
- s->hl = hl;
- s->row = row;
- s->area = area;
- s->first_glyph = row->glyphs[area] + start;
- s->height = row->height;
- s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
-
- /* Display the internal border below the tool-bar window. */
- if (s->w == XWINDOW (s->f->tool_bar_window))
- s->y -= s->f->output_data.x->internal_border_width;
-
- s->ybase = s->y + row->ascent;
-}
-
-
-/* Set background width of glyph string S. START is the index of the
- first glyph following S. LAST_X is the right-most x-position + 1
- in the drawing area. */
-
-static INLINE void
-x_set_glyph_string_background_width (s, start, last_x)
- struct glyph_string *s;
- int start;
- int last_x;
-{
- /* If the face of this glyph string has to be drawn to the end of
- the drawing area, set S->extends_to_end_of_line_p. */
- struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
-
- if (start == s->row->used[s->area]
- && s->area == TEXT_AREA
- && ((s->hl == DRAW_NORMAL_TEXT
- && (s->row->fill_line_p
- || s->face->background != default_face->background
- || s->face->stipple != default_face->stipple
- || s->row->mouse_face_p))
- || s->hl == DRAW_MOUSE_FACE
- || ((s->hl == DRAW_IMAGE_RAISED || s->hl == DRAW_IMAGE_SUNKEN)
- && s->row->fill_line_p)))
- s->extends_to_end_of_line_p = 1;
-
- /* If S extends its face to the end of the line, set its
- background_width to the distance to the right edge of the drawing
- area. */
- if (s->extends_to_end_of_line_p)
- s->background_width = last_x - s->x + 1;
- else
- s->background_width = s->width;
-}
-
-
-/* Add a glyph string for a stretch glyph to the list of strings
- between HEAD and TAIL. START is the index of the stretch glyph in
- row area AREA of glyph row ROW. END is the index of the last glyph
- in that glyph row area. X is the current output position assigned
- to the new glyph string constructed. HL overrides that face of the
- glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
- is the right-most x-position of the drawing area. */
-
-/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
- and below -- keep them on one line. */
-#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
- do \
- { \
- s = (struct glyph_string *) alloca (sizeof *s); \
- x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
- START = x_fill_stretch_glyph_string (s, ROW, AREA, START, END); \
- x_append_glyph_string (&HEAD, &TAIL, s); \
- s->x = (X); \
- } \
- while (0)
-
-
-/* Add a glyph string for an image glyph to the list of strings
- between HEAD and TAIL. START is the index of the image glyph in
- row area AREA of glyph row ROW. END is the index of the last glyph
- in that glyph row area. X is the current output position assigned
- to the new glyph string constructed. HL overrides that face of the
- glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
- is the right-most x-position of the drawing area. */
-
-#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X) \
- do \
- { \
- s = (struct glyph_string *) alloca (sizeof *s); \
- x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL); \
- x_fill_image_glyph_string (s); \
- x_append_glyph_string (&HEAD, &TAIL, s); \
- ++START; \
- s->x = (X); \
- } \
- while (0)
-
-
-/* Add a glyph string for a sequence of character glyphs to the list
- of strings between HEAD and TAIL. START is the index of the first
- glyph in row area AREA of glyph row ROW that is part of the new
- glyph string. END is the index of the last glyph in that glyph row
- area. X is the current output position assigned to the new glyph
- string constructed. HL overrides that face of the glyph; e.g. it
- is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
- right-most x-position of the drawing area. */
-
-#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
- do \
- { \
- int c, face_id; \
- XChar2b *char2b; \
- \
- c = (ROW)->glyphs[AREA][START].u.ch; \
- face_id = (ROW)->glyphs[AREA][START].face_id; \
- \
- s = (struct glyph_string *) alloca (sizeof *s); \
- char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
- x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
- x_append_glyph_string (&HEAD, &TAIL, s); \
- s->x = (X); \
- START = x_fill_glyph_string (s, face_id, START, END, \
- OVERLAPS_P); \
- } \
- while (0)
-
-
-/* Add a glyph string for a composite sequence to the list of strings
- between HEAD and TAIL. START is the index of the first glyph in
- row area AREA of glyph row ROW that is part of the new glyph
- string. END is the index of the last glyph in that glyph row area.
- X is the current output position assigned to the new glyph string
- constructed. HL overrides that face of the glyph; e.g. it is
- DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
- x-position of the drawing area. */
-
-#define BUILD_COMPOSITE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
- do { \
- int cmp_id = (ROW)->glyphs[AREA][START].u.cmp_id; \
- int face_id = (ROW)->glyphs[AREA][START].face_id; \
- struct face *base_face = FACE_FROM_ID (XFRAME (w->frame), face_id); \
- struct composition *cmp = composition_table[cmp_id]; \
- int glyph_len = cmp->glyph_len; \
- XChar2b *char2b; \
- struct face **faces; \
- struct glyph_string *first_s = NULL; \
- int n; \
- \
- base_face = base_face->ascii_face; \
- char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
- faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
- /* At first, fill in `char2b' and `faces'. */ \
- for (n = 0; n < glyph_len; n++) \
- { \
- int c = COMPOSITION_GLYPH (cmp, n); \
- int this_face_id = FACE_FOR_CHAR (XFRAME (w->frame), base_face, c); \
- faces[n] = FACE_FROM_ID (XFRAME (w->frame), this_face_id); \
- x_get_char_face_and_encoding (XFRAME (w->frame), c, \
- this_face_id, char2b + n, 1, 1); \
- } \
- \
- /* Make glyph_strings for each glyph sequence that is drawable by \
- the same face, and append them to HEAD/TAIL. */ \
- for (n = 0; n < cmp->glyph_len;) \
- { \
- s = (struct glyph_string *) alloca (sizeof *s); \
- x_init_glyph_string (s, char2b + n, W, ROW, AREA, START, HL); \
- x_append_glyph_string (&(HEAD), &(TAIL), s); \
- s->cmp = cmp; \
- s->gidx = n; \
- s->x = (X); \
- \
- if (n == 0) \
- first_s = s; \
- \
- n = x_fill_composite_glyph_string (s, faces, OVERLAPS_P); \
- } \
- \
- ++START; \
- s = first_s; \
- } while (0)
-
-
-/* Build a list of glyph strings between HEAD and TAIL for the glyphs
- of AREA of glyph row ROW on window W between indices START and END.
- HL overrides the face for drawing glyph strings, e.g. it is
- DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
- x-positions of the drawing area.
-
- This is an ugly monster macro construct because we must use alloca
- to allocate glyph strings (because x_draw_glyphs can be called
- asynchronously). */
-
-#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, X, LAST_X, OVERLAPS_P) \
- do \
- { \
- HEAD = TAIL = NULL; \
- while (START < END) \
- { \
- struct glyph *first_glyph = (ROW)->glyphs[AREA] + START; \
- switch (first_glyph->type) \
- { \
- case CHAR_GLYPH: \
- BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
- TAIL, HL, X, LAST_X, \
- OVERLAPS_P); \
- break; \
- \
- case COMPOSITE_GLYPH: \
- BUILD_COMPOSITE_GLYPH_STRING (W, ROW, AREA, START, END, \
- HEAD, TAIL, HL, X, LAST_X,\
- OVERLAPS_P); \
- break; \
- \
- case STRETCH_GLYPH: \
- BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END, \
- HEAD, TAIL, HL, X, LAST_X); \
- break; \
- \
- case IMAGE_GLYPH: \
- BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
- TAIL, HL, X, LAST_X); \
- break; \
- \
- default: \
- abort (); \
- } \
- \
- x_set_glyph_string_background_width (s, START, LAST_X); \
- (X) += s->width; \
- } \
- } \
- while (0)
-
-
-/* Draw glyphs between START and END in AREA of ROW on window W,
- starting at x-position X. X is relative to AREA in W. HL is a
- face-override with the following meaning:
-
- DRAW_NORMAL_TEXT draw normally
- DRAW_CURSOR draw in cursor face
- DRAW_MOUSE_FACE draw in mouse face.
- DRAW_INVERSE_VIDEO draw in mode line face
- DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
- DRAW_IMAGE_RAISED draw an image with a raised relief around it
-
- If OVERLAPS_P is non-zero, draw only the foreground of characters
- and clip to the physical height of ROW.
-
- Value is the x-position reached, relative to AREA of W. */
-
-static int
-x_draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
- struct window *w;
- int x;
- struct glyph_row *row;
- enum glyph_row_area area;
- int start, end;
- enum draw_glyphs_face hl;
- int overlaps_p;
-{
- struct glyph_string *head, *tail;
- struct glyph_string *s;
- int last_x, area_width;
- int x_reached;
- int i, j;
-
- /* Let's rather be paranoid than getting a SEGV. */
- end = min (end, row->used[area]);
- start = max (0, start);
- start = min (end, start);
-
- /* Translate X to frame coordinates. Set last_x to the right
- end of the drawing area. */
- if (row->full_width_p)
- {
- /* X is relative to the left edge of W, without scroll bars
- or fringes. */
- struct frame *f = XFRAME (w->frame);
- int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
-
- x += window_left_x;
- area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
- last_x = window_left_x + area_width;
-
- if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
- {
- int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
- if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
- last_x += width;
- else
- x -= width;
- }
-
- x += FRAME_INTERNAL_BORDER_WIDTH (f);
- last_x += FRAME_INTERNAL_BORDER_WIDTH (f);
- }
- else
- {
- x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
- area_width = window_box_width (w, area);
- last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
- }
-
- /* Build a doubly-linked list of glyph_string structures between
- head and tail from what we have to draw. Note that the macro
- BUILD_GLYPH_STRINGS will modify its start parameter. That's
- the reason we use a separate variable `i'. */
- i = start;
- BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
- overlaps_p);
- if (tail)
- x_reached = tail->x + tail->background_width;
- else
- x_reached = x;
-
- /* If there are any glyphs with lbearing < 0 or rbearing > width in
- the row, redraw some glyphs in front or following the glyph
- strings built above. */
- if (head && !overlaps_p && row->contains_overlapping_glyphs_p)
- {
- int dummy_x = 0;
- struct glyph_string *h, *t;
-
- /* Compute overhangs for all glyph strings. */
- for (s = head; s; s = s->next)
- x_compute_glyph_string_overhangs (s);
-
- /* Prepend glyph strings for glyphs in front of the first glyph
- string that are overwritten because of the first glyph
- string's left overhang. The background of all strings
- prepended must be drawn because the first glyph string
- draws over it. */
- i = x_left_overwritten (head);
- if (i >= 0)
- {
- j = i;
- BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
- DRAW_NORMAL_TEXT, dummy_x, last_x,
- overlaps_p);
- start = i;
- x_compute_overhangs_and_x (t, head->x, 1);
- x_prepend_glyph_string_lists (&head, &tail, h, t);
- }
-
- /* Prepend glyph strings for glyphs in front of the first glyph
- string that overwrite that glyph string because of their
- right overhang. For these strings, only the foreground must
- be drawn, because it draws over the glyph string at `head'.
- The background must not be drawn because this would overwrite
- right overhangs of preceding glyphs for which no glyph
- strings exist. */
- i = x_left_overwriting (head);
- if (i >= 0)
- {
- BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
- DRAW_NORMAL_TEXT, dummy_x, last_x,
- overlaps_p);
- for (s = h; s; s = s->next)
- s->background_filled_p = 1;
- x_compute_overhangs_and_x (t, head->x, 1);
- x_prepend_glyph_string_lists (&head, &tail, h, t);
- }
-
- /* Append glyphs strings for glyphs following the last glyph
- string tail that are overwritten by tail. The background of
- these strings has to be drawn because tail's foreground draws
- over it. */
- i = x_right_overwritten (tail);
- if (i >= 0)
- {
- BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
- DRAW_NORMAL_TEXT, x, last_x,
- overlaps_p);
- x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
- x_append_glyph_string_lists (&head, &tail, h, t);
- }
-
- /* Append glyph strings for glyphs following the last glyph
- string tail that overwrite tail. The foreground of such
- glyphs has to be drawn because it writes into the background
- of tail. The background must not be drawn because it could
- paint over the foreground of following glyphs. */
- i = x_right_overwriting (tail);
- if (i >= 0)
- {
- BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
- DRAW_NORMAL_TEXT, x, last_x,
- overlaps_p);
- for (s = h; s; s = s->next)
- s->background_filled_p = 1;
- x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
- x_append_glyph_string_lists (&head, &tail, h, t);
- }
- }
-
- /* Draw all strings. */
- for (s = head; s; s = s->next)
- x_draw_glyph_string (s);
-
- if (area == TEXT_AREA
- && !row->full_width_p
- /* When drawing overlapping rows, only the glyph strings'
- foreground is drawn, which doesn't erase a cursor
- completely. */
- && !overlaps_p)
- {
- int x0 = head ? head->x : x;
- int x1 = tail ? tail->x + tail->background_width : x;
-
- x0 = FRAME_TO_WINDOW_PIXEL_X (w, x0);
- x1 = FRAME_TO_WINDOW_PIXEL_X (w, x1);
-
- if (XFASTINT (w->left_margin_width) != 0)
- {
- int left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
- x0 -= left_area_width;
- x1 -= left_area_width;
- }
-
- notice_overwritten_cursor (w, area, x0, x1,
- row->y, MATRIX_ROW_BOTTOM_Y (row));
- }
-
- /* Value is the x-position up to which drawn, relative to AREA of W.
- This doesn't include parts drawn because of overhangs. */
- x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
- if (!row->full_width_p)
- {
- if (area > LEFT_MARGIN_AREA && XFASTINT (w->left_margin_width) != 0)
- x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
- if (area > TEXT_AREA)
- x_reached -= window_box_width (w, TEXT_AREA);
- }
-
- return x_reached;
-}
-
-
-/* Fix the display of area AREA of overlapping row ROW in window W. */
-
-static void
-x_fix_overlapping_area (w, row, area)
- struct window *w;
- struct glyph_row *row;
- enum glyph_row_area area;
-{
- int i, x;
-
- BLOCK_INPUT;
-
- if (area == LEFT_MARGIN_AREA)
- x = 0;
- else if (area == TEXT_AREA)
- x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
- else
- x = (window_box_width (w, LEFT_MARGIN_AREA)
- + window_box_width (w, TEXT_AREA));
-
- for (i = 0; i < row->used[area];)
- {
- if (row->glyphs[area][i].overlaps_vertically_p)
- {
- int start = i, start_x = x;
-
- do
- {
- x += row->glyphs[area][i].pixel_width;
- ++i;
- }
- while (i < row->used[area]
- && row->glyphs[area][i].overlaps_vertically_p);
-
- x_draw_glyphs (w, start_x, row, area, start, i,
- DRAW_NORMAL_TEXT, 1);
- }
- else
- {
- x += row->glyphs[area][i].pixel_width;
- ++i;
- }
- }
-
- UNBLOCK_INPUT;
-}
-
-
-/* Output LEN glyphs starting at START at the nominal cursor position.
- Advance the nominal cursor over the text. The global variable
- updated_window contains the window being updated, updated_row is
- the glyph row being updated, and updated_area is the area of that
- row being updated. */
-
-static void
-x_write_glyphs (start, len)
- struct glyph *start;
- int len;
-{
- int x, hpos;
-
- xassert (updated_window && updated_row);
- BLOCK_INPUT;
-
- /* Write glyphs. */
-
- hpos = start - updated_row->glyphs[updated_area];
- x = x_draw_glyphs (updated_window, output_cursor.x,
- updated_row, updated_area,
- hpos, hpos + len,
- DRAW_NORMAL_TEXT, 0);
-
- /* Invalidate old phys cursor if the glyph at its hpos is redrawn. */
- if (updated_area == TEXT_AREA
- && updated_window->phys_cursor_on_p
- && updated_window->phys_cursor.vpos == output_cursor.vpos
- && updated_window->phys_cursor.hpos >= hpos
- && updated_window->phys_cursor.hpos < hpos + len)
- updated_window->phys_cursor_on_p = 0;
-
- UNBLOCK_INPUT;
-
- /* Advance the output cursor. */
- output_cursor.hpos += len;
- output_cursor.x = x;
-}
-
-
-/* Insert LEN glyphs from START at the nominal cursor position. */
-
-static void
-x_insert_glyphs (start, len)
- struct glyph *start;
- register int len;
-{
- struct frame *f;
- struct window *w;
- int line_height, shift_by_width, shifted_region_width;
- struct glyph_row *row;
- struct glyph *glyph;
- int frame_x, frame_y, hpos;
-
- xassert (updated_window && updated_row);
- BLOCK_INPUT;
- w = updated_window;
- f = XFRAME (WINDOW_FRAME (w));
-
- /* Get the height of the line we are in. */
- row = updated_row;
- line_height = row->height;
-
- /* Get the width of the glyphs to insert. */
- shift_by_width = 0;
- for (glyph = start; glyph < start + len; ++glyph)
- shift_by_width += glyph->pixel_width;
-
- /* Get the width of the region to shift right. */
- shifted_region_width = (window_box_width (w, updated_area)
- - output_cursor.x
- - shift_by_width);
-
- /* Shift right. */
- frame_x = window_box_left (w, updated_area) + output_cursor.x;
- frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
- XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
- f->output_data.x->normal_gc,
- frame_x, frame_y,
- shifted_region_width, line_height,
- frame_x + shift_by_width, frame_y);
-
- /* Write the glyphs. */
- hpos = start - row->glyphs[updated_area];
- x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
- DRAW_NORMAL_TEXT, 0);
-
- /* Advance the output cursor. */
- output_cursor.hpos += len;
- output_cursor.x += shift_by_width;
- UNBLOCK_INPUT;
-}
-
-
-/* Delete N glyphs at the nominal cursor position. Not implemented
- for X frames. */
-
-static void
-x_delete_glyphs (n)
- register int n;
-{
- abort ();
-}
-
-
-/* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
- If they are <= 0, this is probably an error. */
-
-void
-x_clear_area (dpy, window, x, y, width, height, exposures)
- Display *dpy;
- Window window;
- int x, y;
- int width, height;
- int exposures;
-{
- xassert (width > 0 && height > 0);
- XClearArea (dpy, window, x, y, width, height, exposures);
-}
-
-
-/* Erase the current text line from the nominal cursor position
- (inclusive) to pixel column TO_X (exclusive). The idea is that
- everything from TO_X onward is already erased.
-
- TO_X is a pixel position relative to updated_area of
- updated_window. TO_X == -1 means clear to the end of this area. */
-
-static void
-x_clear_end_of_line (to_x)
- int to_x;
-{
- struct frame *f;
- struct window *w = updated_window;
- int max_x, min_y, max_y;
- int from_x, from_y, to_y;
-
- xassert (updated_window && updated_row);
- f = XFRAME (w->frame);
-
- if (updated_row->full_width_p)
- {
- max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
- if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
- && !w->pseudo_window_p)
- max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
- }
- else
- max_x = window_box_width (w, updated_area);
- max_y = window_text_bottom_y (w);
-
- /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
- of window. For TO_X > 0, truncate to end of drawing area. */
- if (to_x == 0)
- return;
- else if (to_x < 0)
- to_x = max_x;
- else
- to_x = min (to_x, max_x);
-
- to_y = min (max_y, output_cursor.y + updated_row->height);
-
- /* Notice if the cursor will be cleared by this operation. */
- if (!updated_row->full_width_p)
- notice_overwritten_cursor (w, updated_area,
- output_cursor.x, -1,
- updated_row->y,
- MATRIX_ROW_BOTTOM_Y (updated_row));
-
- from_x = output_cursor.x;
-
- /* Translate to frame coordinates. */
- if (updated_row->full_width_p)
- {
- from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
- to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
- }
- else
- {
- from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
- to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
- }
-
- min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
- from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
- to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
-
- /* Prevent inadvertently clearing to end of the X window. */
- if (to_x > from_x && to_y > from_y)
- {
- BLOCK_INPUT;
- x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- from_x, from_y, to_x - from_x, to_y - from_y,
- False);
- UNBLOCK_INPUT;
- }
-}
-
-
-/* Clear entire frame. If updating_frame is non-null, clear that
- frame. Otherwise clear the selected frame. */
-
-static void
-x_clear_frame ()
-{
- struct frame *f;
-
- if (updating_frame)
- f = updating_frame;
- else
- f = SELECTED_FRAME ();
-
- /* Clearing the frame will erase any cursor, so mark them all as no
- longer visible. */
- mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
- output_cursor.hpos = output_cursor.vpos = 0;
- output_cursor.x = -1;
-
- /* We don't set the output cursor here because there will always
- follow an explicit cursor_to. */
- BLOCK_INPUT;
- XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
-
- /* We have to clear the scroll bars, too. If we have changed
- colors or something like that, then they should be notified. */
- x_scroll_bar_clear (f);
-
- XFlush (FRAME_X_DISPLAY (f));
- UNBLOCK_INPUT;
-}
-
-
-\f
-/* Invert the middle quarter of the frame for .15 sec. */
-
-/* We use the select system call to do the waiting, so we have to make
- sure it's available. If it isn't, we just won't do visual bells. */
-
-#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
-
-
-/* Subtract the `struct timeval' values X and Y, storing the result in
- *RESULT. Return 1 if the difference is negative, otherwise 0. */
-
-static int
-timeval_subtract (result, x, y)
- struct timeval *result, x, y;
-{
- /* Perform the carry for the later subtraction by updating y. This
- is safer because on some systems the tv_sec member is unsigned. */
- if (x.tv_usec < y.tv_usec)
- {
- int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
- y.tv_usec -= 1000000 * nsec;
- y.tv_sec += nsec;
- }
-
- if (x.tv_usec - y.tv_usec > 1000000)
- {
- int nsec = (y.tv_usec - x.tv_usec) / 1000000;
- y.tv_usec += 1000000 * nsec;
- y.tv_sec -= nsec;
- }
-
- /* Compute the time remaining to wait. tv_usec is certainly
- positive. */
- result->tv_sec = x.tv_sec - y.tv_sec;
- result->tv_usec = x.tv_usec - y.tv_usec;
-
- /* Return indication of whether the result should be considered
- negative. */
- return x.tv_sec < y.tv_sec;
-}
-
-void
-XTflash (f)
- struct frame *f;
-{
- BLOCK_INPUT;
-
- {
- GC gc;
-
- /* Create a GC that will use the GXxor function to flip foreground
- pixels into background pixels. */
- {
- XGCValues values;
-
- values.function = GXxor;
- values.foreground = (f->output_data.x->foreground_pixel
- ^ f->output_data.x->background_pixel);
-
- gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- GCFunction | GCForeground, &values);
- }
-
- {
- /* Get the height not including a menu bar widget. */
- int height = CHAR_TO_PIXEL_HEIGHT (f, FRAME_HEIGHT (f));
- /* Height of each line to flash. */
- int flash_height = FRAME_LINE_HEIGHT (f);
- /* These will be the left and right margins of the rectangles. */
- int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
- int flash_right = PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);
-
- int width;
-
- /* Don't flash the area between a scroll bar and the frame
- edge it is next to. */
- switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
- {
- case vertical_scroll_bar_left:
- flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
- break;
-
- case vertical_scroll_bar_right:
- flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
- break;
-
- default:
- break;
- }
-
- width = flash_right - flash_left;
-
- /* If window is tall, flash top and bottom line. */
- if (height > 3 * FRAME_LINE_HEIGHT (f))
- {
- XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
- flash_left,
- (FRAME_INTERNAL_BORDER_WIDTH (f)
- + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
- width, flash_height);
- XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
- flash_left,
- (height - flash_height
- - FRAME_INTERNAL_BORDER_WIDTH (f)),
- width, flash_height);
- }
- else
- /* If it is short, flash it all. */
- XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
- flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
- width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
-
- x_flush (f);
-
- {
- struct timeval wakeup;
-
- EMACS_GET_TIME (wakeup);
-
- /* Compute time to wait until, propagating carry from usecs. */
- wakeup.tv_usec += 150000;
- wakeup.tv_sec += (wakeup.tv_usec / 1000000);
- wakeup.tv_usec %= 1000000;
-
- /* Keep waiting until past the time wakeup or any input gets
- available. */
- while (! detect_input_pending ())
- {
- struct timeval current;
- struct timeval timeout;
-
- EMACS_GET_TIME (current);
-
- /* Break if result would be negative. */
- if (timeval_subtract (¤t, wakeup, current))
- break;
-
- /* How long `select' should wait. */
- timeout.tv_sec = 0;
- timeout.tv_usec = 10000;
-
- /* Try to wait that long--but we might wake up sooner. */
- select (0, NULL, NULL, NULL, &timeout);
- }
- }
-
- /* If window is tall, flash top and bottom line. */
- if (height > 3 * FRAME_LINE_HEIGHT (f))
- {
- XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
- flash_left,
- (FRAME_INTERNAL_BORDER_WIDTH (f)
- + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
- width, flash_height);
- XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
- flash_left,
- (height - flash_height
- - FRAME_INTERNAL_BORDER_WIDTH (f)),
- width, flash_height);
- }
- else
- /* If it is short, flash it all. */
- XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
- flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
- width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
-
- XFreeGC (FRAME_X_DISPLAY (f), gc);
- x_flush (f);
- }
- }
-
- UNBLOCK_INPUT;
-}
-
-#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
-
-
-/* Make audible bell. */
-
-void
-XTring_bell ()
-{
- struct frame *f = SELECTED_FRAME ();
-
- if (FRAME_X_DISPLAY (f))
- {
-#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
- if (visible_bell)
- XTflash (f);
- else
-#endif
- {
- BLOCK_INPUT;
- XBell (FRAME_X_DISPLAY (f), 0);
- XFlush (FRAME_X_DISPLAY (f));
- UNBLOCK_INPUT;
- }
- }
-}
-
-\f
-/* Specify how many text lines, from the top of the window,
- should be affected by insert-lines and delete-lines operations.
- This, and those operations, are used only within an update
- that is bounded by calls to x_update_begin and x_update_end. */
-
-static void
-XTset_terminal_window (n)
- register int n;
-{
- /* This function intentionally left blank. */
-}
-
-
-\f
-/***********************************************************************
- Line Dance
- ***********************************************************************/
-
-/* Perform an insert-lines or delete-lines operation, inserting N
- lines or deleting -N lines at vertical position VPOS. */
-
-static void
-x_ins_del_lines (vpos, n)
- int vpos, n;
-{
- abort ();
-}
-
-
-/* Scroll part of the display as described by RUN. */
-
-static void
-x_scroll_run (w, run)
- struct window *w;
- struct run *run;
-{
- struct frame *f = XFRAME (w->frame);
- int x, y, width, height, from_y, to_y, bottom_y;
-
- /* Get frame-relative bounding box of the text display area of W,
- without mode lines. Include in this box the left and right
- fringe of W. */
- window_box (w, -1, &x, &y, &width, &height);
- width += FRAME_X_FRINGE_WIDTH (f);
- x -= FRAME_X_LEFT_FRINGE_WIDTH (f);
-
- from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
- to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
- bottom_y = y + height;
-
- if (to_y < from_y)
- {
- /* Scrolling up. Make sure we don't copy part of the mode
- line at the bottom. */
- if (from_y + run->height > bottom_y)
- height = bottom_y - from_y;
- else
- height = run->height;
- }
- else
- {
- /* Scolling down. Make sure we don't copy over the mode line.
- at the bottom. */
- if (to_y + run->height > bottom_y)
- height = bottom_y - to_y;
- else
- height = run->height;
- }
-
- BLOCK_INPUT;
-
- /* Cursor off. Will be switched on again in x_update_window_end. */
- updated_window = w;
- x_clear_cursor (w);
-
- XCopyArea (FRAME_X_DISPLAY (f),
- FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
- f->output_data.x->normal_gc,
- x, from_y,
- width, height,
- x, to_y);
-
- UNBLOCK_INPUT;
-}
-
-
-\f
-/***********************************************************************
- Exposure Events
- ***********************************************************************/
-
-/* Redisplay an exposed area of frame F. X and Y are the upper-left
- corner of the exposed rectangle. W and H are width and height of
- the exposed area. All are pixel values. W or H zero means redraw
- the entire frame. */
-
-static void
-expose_frame (f, x, y, w, h)
- struct frame *f;
- int x, y, w, h;
-{
- XRectangle r;
- int mouse_face_overwritten_p = 0;
-
- TRACE ((stderr, "expose_frame "));
-
- /* No need to redraw if frame will be redrawn soon. */
- if (FRAME_GARBAGED_P (f))
- {
- TRACE ((stderr, " garbaged\n"));
- return;
- }
-
- /* If basic faces haven't been realized yet, there is no point in
- trying to redraw anything. This can happen when we get an expose
- event while Emacs is starting, e.g. by moving another window. */
- if (FRAME_FACE_CACHE (f) == NULL
- || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
- {
- TRACE ((stderr, " no faces\n"));
- return;
- }
-
- if (w == 0 || h == 0)
- {
- r.x = r.y = 0;
- r.width = CANON_X_UNIT (f) * f->width;
- r.height = CANON_Y_UNIT (f) * f->height;
- }
- else
- {
- r.x = x;
- r.y = y;
- r.width = w;
- r.height = h;
- }
-
- TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
- mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), &r);
-
- if (WINDOWP (f->tool_bar_window))
- mouse_face_overwritten_p
- |= expose_window (XWINDOW (f->tool_bar_window), &r);
-
-#ifndef USE_X_TOOLKIT
- if (WINDOWP (f->menu_bar_window))
- mouse_face_overwritten_p
- |= expose_window (XWINDOW (f->menu_bar_window), &r);
-#endif /* not USE_X_TOOLKIT */
-
- /* Some window managers support a focus-follows-mouse style with
- delayed raising of frames. Imagine a partially obscured frame,
- and moving the mouse into partially obscured mouse-face on that
- frame. The visible part of the mouse-face will be highlighted,
- then the WM raises the obscured frame. With at least one WM, KDE
- 2.1, Emacs is not getting any event for the raising of the frame
- (even tried with SubstructureRedirectMask), only Expose events.
- These expose events will draw text normally, i.e. not
- highlighted. Which means we must redo the highlight here.
- Subsume it under ``we love X''. --gerd 2001-08-15 */
- if (mouse_face_overwritten_p && !FRAME_GARBAGED_P (f))
- {
- struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
- if (f == dpyinfo->mouse_face_mouse_frame)
- {
- int x = dpyinfo->mouse_face_mouse_x;
- int y = dpyinfo->mouse_face_mouse_y;
- clear_mouse_face (dpyinfo);
- note_mouse_highlight (f, x, y);
- }
- }
-}
-
-
-/* Redraw (parts) of all windows in the window tree rooted at W that
- intersect R. R contains frame pixel coordinates. Value is
- non-zero if the exposure overwrites mouse-face. */
-
-static int
-expose_window_tree (w, r)
- struct window *w;
- XRectangle *r;
-{
- struct frame *f = XFRAME (w->frame);
- int mouse_face_overwritten_p = 0;
-
- while (w && !FRAME_GARBAGED_P (f))
- {
- if (!NILP (w->hchild))
- mouse_face_overwritten_p
- |= expose_window_tree (XWINDOW (w->hchild), r);
- else if (!NILP (w->vchild))
- mouse_face_overwritten_p
- |= expose_window_tree (XWINDOW (w->vchild), r);
- else
- mouse_face_overwritten_p |= expose_window (w, r);
-
- w = NILP (w->next) ? NULL : XWINDOW (w->next);
- }
-
- return mouse_face_overwritten_p;
-}
-
-
-/* Redraw the part of glyph row area AREA of glyph row ROW on window W
- which intersects rectangle R. R is in window-relative coordinates. */
-
-static void
-expose_area (w, row, r, area)
- struct window *w;
- struct glyph_row *row;
- XRectangle *r;
- enum glyph_row_area area;
-{
- struct glyph *first = row->glyphs[area];
- struct glyph *end = row->glyphs[area] + row->used[area];
- struct glyph *last;
- int first_x, start_x, x;
-
- if (area == TEXT_AREA && row->fill_line_p)
- /* If row extends face to end of line write the whole line. */
- x_draw_glyphs (w, 0, row, area, 0, row->used[area],
- DRAW_NORMAL_TEXT, 0);
- else
- {
- /* Set START_X to the window-relative start position for drawing glyphs of
- AREA. The first glyph of the text area can be partially visible.
- The first glyphs of other areas cannot. */
- if (area == LEFT_MARGIN_AREA)
- start_x = 0;
- else if (area == TEXT_AREA)
- start_x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
- else
- start_x = (window_box_width (w, LEFT_MARGIN_AREA)
- + window_box_width (w, TEXT_AREA));
- x = start_x;
-
- /* Find the first glyph that must be redrawn. */
- while (first < end
- && x + first->pixel_width < r->x)
- {
- x += first->pixel_width;
- ++first;
- }
-
- /* Find the last one. */
- last = first;
- first_x = x;
- while (last < end
- && x < r->x + r->width)
- {
- x += last->pixel_width;
- ++last;
- }
-
- /* Repaint. */
- if (last > first)
- x_draw_glyphs (w, first_x - start_x, row, area,
- first - row->glyphs[area],
- last - row->glyphs[area],
- DRAW_NORMAL_TEXT, 0);
- }
-}
-
-
-/* Redraw the parts of the glyph row ROW on window W intersecting
- rectangle R. R is in window-relative coordinates. Value is
- non-zero if mouse-face was overwritten. */
-
-static int
-expose_line (w, row, r)
- struct window *w;
- struct glyph_row *row;
- XRectangle *r;
-{
- xassert (row->enabled_p);
-
- if (row->mode_line_p || w->pseudo_window_p)
- x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
- DRAW_NORMAL_TEXT, 0);
- else
- {
- if (row->used[LEFT_MARGIN_AREA])
- expose_area (w, row, r, LEFT_MARGIN_AREA);
- if (row->used[TEXT_AREA])
- expose_area (w, row, r, TEXT_AREA);
- if (row->used[RIGHT_MARGIN_AREA])
- expose_area (w, row, r, RIGHT_MARGIN_AREA);
- x_draw_row_fringe_bitmaps (w, row);
- }
-
- return row->mouse_face_p;
-}
-
-
-/* Return non-zero if W's cursor intersects rectangle R. */
-
-static int
-x_phys_cursor_in_rect_p (w, r)
- struct window *w;
- XRectangle *r;
-{
- XRectangle cr, result;
- struct glyph *cursor_glyph;
-
- cursor_glyph = get_phys_cursor_glyph (w);
- if (cursor_glyph)
- {
- cr.x = w->phys_cursor.x;
- cr.y = w->phys_cursor.y;
- cr.width = cursor_glyph->pixel_width;
- cr.height = w->phys_cursor_height;
- return x_intersect_rectangles (&cr, r, &result);
- }
- else
- return 0;
-}
-
-
-/* Redraw those parts of glyphs rows during expose event handling that
- overlap other rows. Redrawing of an exposed line writes over parts
- of lines overlapping that exposed line; this function fixes that.
-
- W is the window being exposed. FIRST_OVERLAPPING_ROW is the first
- row in W's current matrix that is exposed and overlaps other rows.
- LAST_OVERLAPPING_ROW is the last such row. */
-
-static void
-expose_overlaps (w, first_overlapping_row, last_overlapping_row)
- struct window *w;
- struct glyph_row *first_overlapping_row;
- struct glyph_row *last_overlapping_row;
-{
- struct glyph_row *row;
-
- for (row = first_overlapping_row; row <= last_overlapping_row; ++row)
- if (row->overlapping_p)
- {
- xassert (row->enabled_p && !row->mode_line_p);
-
- if (row->used[LEFT_MARGIN_AREA])
- x_fix_overlapping_area (w, row, LEFT_MARGIN_AREA);
-
- if (row->used[TEXT_AREA])
- x_fix_overlapping_area (w, row, TEXT_AREA);
-
- if (row->used[RIGHT_MARGIN_AREA])
- x_fix_overlapping_area (w, row, RIGHT_MARGIN_AREA);
- }
-}
-
-
-/* Redraw the part of window W intersection rectangle FR. Pixel
- coordinates in FR are frame-relative. Call this function with
- input blocked. Value is non-zero if the exposure overwrites
- mouse-face. */
-
-static int
-expose_window (w, fr)
- struct window *w;
- XRectangle *fr;
-{
- struct frame *f = XFRAME (w->frame);
- XRectangle wr, r;
- int mouse_face_overwritten_p = 0;
-
- /* If window is not yet fully initialized, do nothing. This can
- happen when toolkit scroll bars are used and a window is split.
- Reconfiguring the scroll bar will generate an expose for a newly
- created window. */
- if (w->current_matrix == NULL)
- return 0;
-
- /* When we're currently updating the window, display and current
- matrix usually don't agree. Arrange for a thorough display
- later. */
- if (w == updated_window)
- {
- SET_FRAME_GARBAGED (f);
- return 0;
- }
-
- /* Frame-relative pixel rectangle of W. */
- wr.x = XFASTINT (w->left) * CANON_X_UNIT (f);
- wr.y = XFASTINT (w->top) * CANON_Y_UNIT (f);
- wr.width = XFASTINT (w->width) * CANON_X_UNIT (f);
- wr.height = XFASTINT (w->height) * CANON_Y_UNIT (f);
-
- if (x_intersect_rectangles (fr, &wr, &r))
- {
- int yb = window_text_bottom_y (w);
- struct glyph_row *row;
- int cursor_cleared_p;
- struct glyph_row *first_overlapping_row, *last_overlapping_row;
-
- TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
- r.x, r.y, r.width, r.height));
-
- /* Convert to window coordinates. */
- r.x = FRAME_TO_WINDOW_PIXEL_X (w, r.x);
- r.y = FRAME_TO_WINDOW_PIXEL_Y (w, r.y);
-
- /* Turn off the cursor. */
- if (!w->pseudo_window_p
- && x_phys_cursor_in_rect_p (w, &r))
- {
- x_clear_cursor (w);
- cursor_cleared_p = 1;
- }
- else
- cursor_cleared_p = 0;
-
- /* Update lines intersecting rectangle R. */
- first_overlapping_row = last_overlapping_row = NULL;
- for (row = w->current_matrix->rows;
- row->enabled_p;
- ++row)
- {
- int y0 = row->y;
- int y1 = MATRIX_ROW_BOTTOM_Y (row);
-
- if ((y0 >= r.y && y0 < r.y + r.height)
- || (y1 > r.y && y1 < r.y + r.height)
- || (r.y >= y0 && r.y < y1)
- || (r.y + r.height > y0 && r.y + r.height < y1))
- {
- if (row->overlapping_p)
- {
- if (first_overlapping_row == NULL)
- first_overlapping_row = row;
- last_overlapping_row = row;
- }
-
- if (expose_line (w, row, &r))
- mouse_face_overwritten_p = 1;
- }
-
- if (y1 >= yb)
- break;
- }
-
- /* Display the mode line if there is one. */
- if (WINDOW_WANTS_MODELINE_P (w)
- && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
- row->enabled_p)
- && row->y < r.y + r.height)
- {
- if (expose_line (w, row, &r))
- mouse_face_overwritten_p = 1;
- }
-
- if (!w->pseudo_window_p)
- {
- /* Fix the display of overlapping rows. */
- if (first_overlapping_row)
- expose_overlaps (w, first_overlapping_row, last_overlapping_row);
-
- /* Draw border between windows. */
- x_draw_vertical_border (w);
-
- /* Turn the cursor on again. */
- if (cursor_cleared_p)
- x_update_window_cursor (w, 1);
- }
- }
-
- return mouse_face_overwritten_p;
-}
-
-
-/* Determine the intersection of two rectangles R1 and R2. Return
- the intersection in *RESULT. Value is non-zero if RESULT is not
- empty. */
-
-static int
-x_intersect_rectangles (r1, r2, result)
- XRectangle *r1, *r2, *result;
-{
- XRectangle *left, *right;
- XRectangle *upper, *lower;
- int intersection_p = 0;
-
- /* Rearrange so that R1 is the left-most rectangle. */
- if (r1->x < r2->x)
- left = r1, right = r2;
- else
- left = r2, right = r1;
-
- /* X0 of the intersection is right.x0, if this is inside R1,
- otherwise there is no intersection. */
- if (right->x <= left->x + left->width)
- {
- result->x = right->x;
-
- /* The right end of the intersection is the minimum of the
- the right ends of left and right. */
- result->width = (min (left->x + left->width, right->x + right->width)
- - result->x);
-
- /* Same game for Y. */
- if (r1->y < r2->y)
- upper = r1, lower = r2;
- else
- upper = r2, lower = r1;
-
- /* The upper end of the intersection is lower.y0, if this is inside
- of upper. Otherwise, there is no intersection. */
- if (lower->y <= upper->y + upper->height)
- {
- result->y = lower->y;
-
- /* The lower end of the intersection is the minimum of the lower
- ends of upper and lower. */
- result->height = (min (lower->y + lower->height,
- upper->y + upper->height)
- - result->y);
- intersection_p = 1;
- }
- }
-
- return intersection_p;
-}
-
-
-
-
-\f
-static void
-frame_highlight (f)
- struct frame *f;
-{
- /* We used to only do this if Vx_no_window_manager was non-nil, but
- the ICCCM (section 4.1.6) says that the window's border pixmap
- and border pixel are window attributes which are "private to the
- client", so we can always change it to whatever we want. */
- BLOCK_INPUT;
- XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- f->output_data.x->border_pixel);
- UNBLOCK_INPUT;
- x_update_cursor (f, 1);
-}
-
-static void
-frame_unhighlight (f)
- struct frame *f;
-{
- /* We used to only do this if Vx_no_window_manager was non-nil, but
- the ICCCM (section 4.1.6) says that the window's border pixmap
- and border pixel are window attributes which are "private to the
- client", so we can always change it to whatever we want. */
- BLOCK_INPUT;
- XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- f->output_data.x->border_tile);
- UNBLOCK_INPUT;
- x_update_cursor (f, 1);
-}
-
-/* The focus has changed. Update the frames as necessary to reflect
- the new situation. Note that we can't change the selected frame
- here, because the Lisp code we are interrupting might become confused.
- Each event gets marked with the frame in which it occurred, so the
- Lisp code can tell when the switch took place by examining the events. */
-
-static void
-x_new_focus_frame (dpyinfo, frame)
- struct x_display_info *dpyinfo;
- struct frame *frame;
-{
- struct frame *old_focus = dpyinfo->x_focus_frame;
-
- if (frame != dpyinfo->x_focus_frame)
- {
- /* Set this before calling other routines, so that they see
- the correct value of x_focus_frame. */
- dpyinfo->x_focus_frame = frame;
-
- if (old_focus && old_focus->auto_lower)
- x_lower_frame (old_focus);
-
-#if 0
- selected_frame = frame;
- XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
- selected_frame);
- Fselect_window (selected_frame->selected_window);
- choose_minibuf_frame ();
-#endif /* ! 0 */
-
- if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
- pending_autoraise_frame = dpyinfo->x_focus_frame;
- else
- pending_autoraise_frame = 0;
- }
-
- x_frame_rehighlight (dpyinfo);
-}
-
-/* Handle FocusIn and FocusOut state changes for FRAME.
- If FRAME has focus and there exists more than one frame, puts
- a FOCUS_IN_EVENT into BUFP.
- Returns number of events inserted into BUFP. */
-
-static int
-x_focus_changed (type, state, dpyinfo, frame, bufp, numchars)
- int type;
- int state;
- struct x_display_info *dpyinfo;
- struct frame *frame;
- struct input_event *bufp;
- int numchars;
-{
- int nr_events = 0;
-
- if (type == FocusIn)
- {
- if (dpyinfo->x_focus_event_frame != frame)
- {
- x_new_focus_frame (dpyinfo, frame);
- dpyinfo->x_focus_event_frame = frame;
-
- /* Don't stop displaying the initial startup message
- for a switch-frame event we don't need. */
- if (numchars > 0
- && GC_NILP (Vterminal_frame)
- && GC_CONSP (Vframe_list)
- && !GC_NILP (XCDR (Vframe_list)))
- {
- bufp->kind = FOCUS_IN_EVENT;
- XSETFRAME (bufp->frame_or_window, frame);
- bufp->arg = Qnil;
- ++bufp;
- numchars--;
- ++nr_events;
- }
- }
-
- frame->output_data.x->focus_state |= state;
-
-#ifdef HAVE_X_I18N
- if (FRAME_XIC (frame))
- XSetICFocus (FRAME_XIC (frame));
-#endif
- }
- else if (type == FocusOut)
- {
- frame->output_data.x->focus_state &= ~state;
-
- if (dpyinfo->x_focus_event_frame == frame)
- {
- dpyinfo->x_focus_event_frame = 0;
- x_new_focus_frame (dpyinfo, 0);
- }
-
-#ifdef HAVE_X_I18N
- if (FRAME_XIC (frame))
- XUnsetICFocus (FRAME_XIC (frame));
-#endif
- }
-
- return nr_events;
-}
-
-/* The focus may have changed. Figure out if it is a real focus change,
- by checking both FocusIn/Out and Enter/LeaveNotify events.
-
- Returns number of events inserted into BUFP. */
-
-static int
-x_detect_focus_change (dpyinfo, event, bufp, numchars)
- struct x_display_info *dpyinfo;
- XEvent *event;
- struct input_event *bufp;
- int numchars;
-{
- struct frame *frame;
- int nr_events = 0;
-
- frame = x_top_window_to_frame (dpyinfo, event->xany.window);
- if (! frame) return nr_events;
-
- switch (event->type)
- {
- case EnterNotify:
- case LeaveNotify:
- if (event->xcrossing.detail != NotifyInferior
- && event->xcrossing.focus
- && ! (frame->output_data.x->focus_state & FOCUS_EXPLICIT))
- nr_events = x_focus_changed ((event->type == EnterNotify
- ? FocusIn : FocusOut),
- FOCUS_IMPLICIT,
- dpyinfo,
- frame,
- bufp,
- numchars);
- break;
-
- case FocusIn:
- case FocusOut:
- nr_events = x_focus_changed (event->type,
- (event->xfocus.detail == NotifyPointer
- ? FOCUS_IMPLICIT : FOCUS_EXPLICIT),
- dpyinfo,
- frame,
- bufp,
- numchars);
- break;
- }
-
- return nr_events;
-}
-
-
-/* Handle an event saying the mouse has moved out of an Emacs frame. */
-
-void
-x_mouse_leave (dpyinfo)
- struct x_display_info *dpyinfo;
-{
- x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
-}
-
-/* The focus has changed, or we have redirected a frame's focus to
- another frame (this happens when a frame uses a surrogate
- mini-buffer frame). Shift the highlight as appropriate.
-
- The FRAME argument doesn't necessarily have anything to do with which
- frame is being highlighted or un-highlighted; we only use it to find
- the appropriate X display info. */
-
-static void
-XTframe_rehighlight (frame)
- struct frame *frame;
-{
- x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
-}
-
-static void
-x_frame_rehighlight (dpyinfo)
- struct x_display_info *dpyinfo;
-{
- struct frame *old_highlight = dpyinfo->x_highlight_frame;
-
- if (dpyinfo->x_focus_frame)
- {
- dpyinfo->x_highlight_frame
- = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
- ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
- : dpyinfo->x_focus_frame);
- if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
- {
- FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
- dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
- }
- }
- else
- dpyinfo->x_highlight_frame = 0;