X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/b547b6e89b994636ed0d853916585812dc75ae99..8030369ccb5c871d3ce11b96c220f318bc741ed8:/src/xterm.c diff --git a/src/xterm.c b/src/xterm.c index d134162f3c..338fd65613 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -1,5 +1,5 @@ /* X Communication module for terminals which understand the X protocol. - Copyright (C) 1989, 93, 94, 95, 96, 1997, 1998, 1999, 2000, 2001 + Copyright (C) 1989, 93, 94, 95, 96, 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -98,7 +98,7 @@ Boston, MA 02111-1307, USA. */ #endif #ifdef USE_LUCID -extern int xlwmenu_window_p (Widget w, Window window); +extern int xlwmenu_window_p P_ ((Widget w, Window window)); extern void xlwmenu_redisplay P_ ((Widget)); #endif @@ -155,11 +155,11 @@ extern void _XEditResCheckMessages (); #define BETWEEN(X, LOWER, UPPER) ((X) >= (LOWER) && (X) < (UPPER)) -/* Bitmaps for truncated lines. */ +/* Fringe bitmaps. */ -enum bitmap_type +enum fringe_bitmap_type { - NO_BITMAP, + NO_FRINGE_BITMAP, LEFT_TRUNCATION_BITMAP, RIGHT_TRUNCATION_BITMAP, OVERLAY_ARROW_BITMAP, @@ -172,9 +172,17 @@ enum bitmap_type `indicate-empty-lines' is non-nil. */ #define zv_width 8 -#define zv_height 8 +#define zv_height 72 +#define zv_period 3 static unsigned char zv_bits[] = { - 0x00, 0x00, 0x1e, 0x1e, 0x1e, 0x1e, 0x00, 0x00}; + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00}; /* An arrow like this: `<-'. */ @@ -245,6 +253,13 @@ static Lisp_Object previous_help_echo; static int any_help_event_p; +/* Non-zero means autoselect window with the mouse cursor. */ + +int mouse_autoselect_window; + +/* Last window where we saw the mouse. Used by mouse-autoselect-window. */ +static Lisp_Object last_window; + /* Non-zero means draw block and hollow cursor as wide as the glyph under it. For example, if a block cursor is over a tab, it will be drawn as wide as that tab on the display. */ @@ -274,8 +289,6 @@ Lisp_Object x_display_name_list; extern struct frame *updating_frame; -extern int waiting_for_input; - /* This is a frame waiting to be auto-raised, within XTread_socket. */ struct frame *pending_autoraise_frame; @@ -373,9 +386,15 @@ extern int errno; /* A mask of extra modifier bits to put into every keyboard char. */ -extern int extra_keyboard_modifiers; +extern EMACS_INT extra_keyboard_modifiers; + +/* The keysyms to use for the various modifiers. */ + +Lisp_Object Vx_alt_keysym, Vx_hyper_keysym, Vx_meta_keysym, Vx_super_keysym; +static Lisp_Object Qalt, Qhyper, Qmeta, Qsuper, Qmodifier_value; static Lisp_Object Qvendor_specific_keysyms; +static Lisp_Object Qlatin_1, Qutf_8; extern XrmDatabase x_load_resources P_ ((Display *, char *, char *, char *)); extern Lisp_Object x_icon_type P_ ((struct frame *)); @@ -411,7 +430,8 @@ static int fast_find_string_pos P_ ((struct window *, int, Lisp_Object, static void set_output_cursor P_ ((struct cursor_pos *)); static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int, int *, int *, int *, int)); -static void note_mode_line_highlight P_ ((struct window *, int, int)); +static void note_mode_line_or_margin_highlight P_ ((struct window *, int, + int, int)); static void note_mouse_highlight P_ ((struct frame *, int, int)); static void note_tool_bar_highlight P_ ((struct frame *f, int, int)); static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *)); @@ -446,14 +466,27 @@ static void x_clear_cursor P_ ((struct window *)); static void frame_highlight P_ ((struct frame *)); static void frame_unhighlight P_ ((struct frame *)); static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *)); +static int x_focus_changed P_ ((int, + int, + struct x_display_info *, + struct frame *, + struct input_event *, + int)); +static int x_detect_focus_change P_ ((struct x_display_info *, + XEvent *, + struct input_event *, + int)); static void XTframe_rehighlight P_ ((struct frame *)); static void x_frame_rehighlight P_ ((struct x_display_info *)); static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *)); -static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int)); +static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int, + enum text_cursor_kinds)); static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *, XRectangle *)); static void expose_frame P_ ((struct frame *, int, int, int, int)); static int expose_window_tree P_ ((struct window *, XRectangle *)); +static void expose_overlaps P_ ((struct window *, struct glyph_row *, + struct glyph_row *)); static int expose_window P_ ((struct window *, XRectangle *)); static void expose_area P_ ((struct window *, struct glyph_row *, XRectangle *, enum glyph_row_area)); @@ -463,14 +496,15 @@ static void x_update_cursor_in_window_tree P_ ((struct window *, int)); static void x_update_window_cursor P_ ((struct window *, int)); static void x_erase_phys_cursor P_ ((struct window *)); void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int)); -static void x_draw_bitmap P_ ((struct window *, struct glyph_row *, - enum bitmap_type)); +static void x_draw_fringe_bitmap P_ ((struct window *, struct glyph_row *, + enum fringe_bitmap_type, int left_p)); static void x_clip_to_row P_ ((struct window *, struct glyph_row *, GC, int)); static int x_phys_cursor_in_rect_p P_ ((struct window *, XRectangle *)); -static void x_draw_row_bitmaps P_ ((struct window *, struct glyph_row *)); -static void notice_overwritten_cursor P_ ((struct window *, int, int)); +static void x_draw_row_fringe_bitmaps P_ ((struct window *, struct glyph_row *)); +static void notice_overwritten_cursor P_ ((struct window *, enum glyph_row_area, + int, int, int, int)); static void x_flush P_ ((struct frame *f)); static void x_update_begin P_ ((struct frame *)); static void x_update_window_begin P_ ((struct window *)); @@ -483,6 +517,8 @@ static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *, enum scroll_bar_part *, Lisp_Object *, Lisp_Object *, unsigned long *)); +static void x_check_fullscreen P_ ((struct frame *)); +static void x_check_fullscreen_move P_ ((struct frame *)); /* Flush display of frame F, or of all frames if F is null. */ @@ -659,7 +695,7 @@ x_draw_vertical_border (w) int x0, x1, y0, y1; window_box_edges (w, -1, &x0, &y0, &x1, &y1); - x1 += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f); + x1 += FRAME_X_RIGHT_FRINGE_WIDTH (f); y1 -= 1; XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), @@ -758,7 +794,7 @@ XTframe_up_to_date (f) /* Draw truncation mark bitmaps, continuation mark bitmaps, overlay - arrow bitmaps, or clear the areas where they would be displayed + arrow bitmaps, or clear the fringes if no bitmaps are required before DESIRED_ROW is made current. The window being updated is found in updated_window. This function It is called from update_window_line only if it is known that there are differences @@ -769,54 +805,68 @@ x_after_update_window_line (desired_row) struct glyph_row *desired_row; { struct window *w = updated_window; + struct frame *f; + int width, height; xassert (w); if (!desired_row->mode_line_p && !w->pseudo_window_p) { - struct frame *f; - int width; - BLOCK_INPUT; - x_draw_row_bitmaps (w, desired_row); - - /* When a window has disappeared, make sure that no rest of - full-width rows stays visible in the internal border. */ - if (windows_or_buffers_changed - && (f = XFRAME (w->frame), - width = FRAME_INTERNAL_BORDER_WIDTH (f), - width != 0)) - { - int height = desired_row->visible_height; - int x = (window_box_right (w, -1) - + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f)); - int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y)); - - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - x, y, width, height, False); - } + x_draw_row_fringe_bitmaps (w, desired_row); + UNBLOCK_INPUT; + } + /* When a window has disappeared, make sure that no rest of + full-width rows stays visible in the internal border. Could + check here if updated_window is the leftmost/rightmost window, + but I guess it's not worth doing since vertically split windows + are almost never used, internal border is rarely set, and the + overhead is very small. */ + if (windows_or_buffers_changed + && desired_row->full_width_p + && (f = XFRAME (w->frame), + width = FRAME_INTERNAL_BORDER_WIDTH (f), + width != 0) + && (height = desired_row->visible_height, + height > 0)) + { + int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y)); + + /* Internal border is drawn below the tool bar. */ + if (WINDOWP (f->tool_bar_window) + && w == XWINDOW (f->tool_bar_window)) + y -= width; + + BLOCK_INPUT; + x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + 0, y, width, height, False); + x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + f->output_data.x->pixel_width - width, + y, width, height, False); UNBLOCK_INPUT; } } -/* Draw the bitmap WHICH in one of the areas to the left or right of +/* Draw the bitmap WHICH in one of the left or right fringes of window W. ROW is the glyph row for which to display the bitmap; it determines the vertical position at which the bitmap has to be drawn. */ static void -x_draw_bitmap (w, row, which) +x_draw_fringe_bitmap (w, row, which, left_p) struct window *w; struct glyph_row *row; - enum bitmap_type which; + enum fringe_bitmap_type which; + int left_p; { struct frame *f = XFRAME (WINDOW_FRAME (w)); Display *display = FRAME_X_DISPLAY (f); Window window = FRAME_X_WINDOW (f); int x, y, wd, h, dy; - unsigned char *bits; + int b1, b2; + unsigned char *bits = NULL; Pixmap pixmap; GC gc = f->output_data.x->normal_gc; struct face *face; @@ -825,93 +875,151 @@ x_draw_bitmap (w, row, which) /* Must clip because of partially visible lines. */ x_clip_to_row (w, row, gc, 1); + /* Convert row to frame coordinates. */ + y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); + switch (which) { + case NO_FRINGE_BITMAP: + wd = 0; + h = 0; + break; + case LEFT_TRUNCATION_BITMAP: wd = left_width; h = left_height; bits = left_bits; - x = (WINDOW_TO_FRAME_PIXEL_X (w, 0) - - wd - - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2); break; case OVERLAY_ARROW_BITMAP: - wd = left_width; - h = left_height; + wd = ov_width; + h = ov_height; bits = ov_bits; - x = (WINDOW_TO_FRAME_PIXEL_X (w, 0) - - wd - - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2); break; case RIGHT_TRUNCATION_BITMAP: wd = right_width; h = right_height; bits = right_bits; - x = window_box_right (w, -1); - x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2; break; case CONTINUED_LINE_BITMAP: - wd = right_width; - h = right_height; + wd = continued_width; + h = continued_height; bits = continued_bits; - x = window_box_right (w, -1); - x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2; break; case CONTINUATION_LINE_BITMAP: wd = continuation_width; h = continuation_height; bits = continuation_bits; - x = (WINDOW_TO_FRAME_PIXEL_X (w, 0) - - wd - - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2); break; case ZV_LINE_BITMAP: wd = zv_width; - h = zv_height; - bits = zv_bits; - x = (WINDOW_TO_FRAME_PIXEL_X (w, 0) - - wd - - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2); + h = zv_height - (y % zv_period); + bits = zv_bits + (y % zv_period); break; default: abort (); } - /* Convert to frame coordinates. Set dy to the offset in the row to - start drawing the bitmap. */ - y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); + /* Clip bitmap if too high. */ + if (h > row->height) + h = row->height; + + /* Set dy to the offset in the row to start drawing the bitmap. */ dy = (row->height - h) / 2; - /* Draw the bitmap. I believe these small pixmaps can be cached - by the server. */ - face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID); - pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h, - face->foreground, - face->background, depth); - XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy); - XFreePixmap (display, pixmap); + face = FACE_FROM_ID (f, FRINGE_FACE_ID); + PREPARE_FACE_FOR_DISPLAY (f, face); + + /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill + the fringe. */ + b1 = b2 = -1; + if (left_p) + { + if (wd > FRAME_X_LEFT_FRINGE_WIDTH (f)) + wd = FRAME_X_LEFT_FRINGE_WIDTH (f); + x = (WINDOW_TO_FRAME_PIXEL_X (w, 0) + - wd + - (FRAME_X_LEFT_FRINGE_WIDTH (f) - wd) / 2); + if (wd < FRAME_X_LEFT_FRINGE_WIDTH (f) || row->height > h) + { + /* If W has a vertical border to its left, don't draw over it. */ + int border = ((XFASTINT (w->left) > 0 + && !FRAME_HAS_VERTICAL_SCROLL_BARS (f)) + ? 1 : 0); + b1 = (window_box_left (w, -1) + - FRAME_X_LEFT_FRINGE_WIDTH (f) + + border); + b2 = (FRAME_X_LEFT_FRINGE_WIDTH (f) - border); + } + } + else + { + if (wd > FRAME_X_RIGHT_FRINGE_WIDTH (f)) + wd = FRAME_X_RIGHT_FRINGE_WIDTH (f); + x = (window_box_right (w, -1) + + (FRAME_X_RIGHT_FRINGE_WIDTH (f) - wd) / 2); + /* Clear right fringe if no bitmap to draw of if bitmap doesn't fill + the fringe. */ + if (wd < FRAME_X_RIGHT_FRINGE_WIDTH (f) || row->height > h) + { + b1 = window_box_right (w, -1); + b2 = FRAME_X_RIGHT_FRINGE_WIDTH (f); + } + } + + if (b1 >= 0) + { + int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w); + + /* In case the same realized face is used for fringes and + for something displayed in the text (e.g. face `region' on + mono-displays, the fill style may have been changed to + FillSolid in x_draw_glyph_string_background. */ + if (face->stipple) + XSetFillStyle (display, face->gc, FillOpaqueStippled); + else + XSetForeground (display, face->gc, face->background); + + XFillRectangle (display, window, face->gc, + b1, + WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, + row->y)), + b2, + row->visible_height); + if (!face->stipple) + XSetForeground (display, face->gc, face->foreground); + } + + if (which != NO_FRINGE_BITMAP) + { + /* Draw the bitmap. I believe these small pixmaps can be cached + by the server. */ + pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h, + face->foreground, + face->background, depth); + XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy); + XFreePixmap (display, pixmap); + } + XSetClipMask (display, gc, None); } -/* Draw flags bitmaps for glyph row ROW on window W. Call this +/* Draw fringe bitmaps for glyph row ROW on window W. Call this function with input blocked. */ static void -x_draw_row_bitmaps (w, row) +x_draw_row_fringe_bitmaps (w, row) struct window *w; struct glyph_row *row; { struct frame *f = XFRAME (w->frame); - enum bitmap_type bitmap; - struct face *face; - int header_line_height = -1; + enum fringe_bitmap_type bitmap; xassert (interrupt_input_blocked); @@ -920,103 +1028,37 @@ x_draw_row_bitmaps (w, row) if (row->visible_height <= 0) return; - face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID); - PREPARE_FACE_FOR_DISPLAY (f, face); - - /* Decide which bitmap to draw at the left side. */ - if (row->overlay_arrow_p) - bitmap = OVERLAY_ARROW_BITMAP; - else if (row->truncated_on_left_p) - bitmap = LEFT_TRUNCATION_BITMAP; - else if (MATRIX_ROW_CONTINUATION_LINE_P (row)) - bitmap = CONTINUATION_LINE_BITMAP; - else if (row->indicate_empty_line_p) - bitmap = ZV_LINE_BITMAP; - else - bitmap = NO_BITMAP; - - /* Clear flags area if no bitmap to draw or if bitmap doesn't fill - the flags area. */ - if (bitmap == NO_BITMAP - || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f)) - { - /* If W has a vertical border to its left, don't draw over it. */ - int border = ((XFASTINT (w->left) > 0 - && !FRAME_HAS_VERTICAL_SCROLL_BARS (f)) - ? 1 : 0); - int left = window_box_left (w, -1); - - if (header_line_height < 0) - header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w); - - /* In case the same realized face is used for bitmap areas and - for something displayed in the text (e.g. face `region' on - mono-displays, the fill style may have been changed to - FillSolid in x_draw_glyph_string_background. */ - if (face->stipple) - XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled); + if (FRAME_X_LEFT_FRINGE_WIDTH (f) != 0) + { + /* Decide which bitmap to draw in the left fringe. */ + if (row->overlay_arrow_p) + bitmap = OVERLAY_ARROW_BITMAP; + else if (row->truncated_on_left_p) + bitmap = LEFT_TRUNCATION_BITMAP; + else if (MATRIX_ROW_CONTINUATION_LINE_P (row)) + bitmap = CONTINUATION_LINE_BITMAP; + else if (row->indicate_empty_line_p) + bitmap = ZV_LINE_BITMAP; else - XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background); - - XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - face->gc, - (left - - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - + border), - WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, - row->y)), - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - border, - row->visible_height); - if (!face->stipple) - XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground); - } - - /* Draw the left bitmap. */ - if (bitmap != NO_BITMAP) - x_draw_bitmap (w, row, bitmap); + bitmap = NO_FRINGE_BITMAP; - /* Decide which bitmap to draw at the right side. */ - if (row->truncated_on_right_p) - bitmap = RIGHT_TRUNCATION_BITMAP; - else if (row->continued_p) - bitmap = CONTINUED_LINE_BITMAP; - else - bitmap = NO_BITMAP; + x_draw_fringe_bitmap (w, row, bitmap, 1); + } - /* Clear flags area if no bitmap to draw of if bitmap doesn't fill - the flags area. */ - if (bitmap == NO_BITMAP - || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f)) + if (FRAME_X_RIGHT_FRINGE_WIDTH (f) != 0) { - int right = window_box_right (w, -1); - - if (header_line_height < 0) - header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w); - - /* In case the same realized face is used for bitmap areas and - for something displayed in the text (e.g. face `region' on - mono-displays, the fill style may have been changed to - FillSolid in x_draw_glyph_string_background. */ - if (face->stipple) - XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled); + /* Decide which bitmap to draw in the right fringe. */ + if (row->truncated_on_right_p) + bitmap = RIGHT_TRUNCATION_BITMAP; + else if (row->continued_p) + bitmap = CONTINUED_LINE_BITMAP; + else if (row->indicate_empty_line_p && FRAME_X_LEFT_FRINGE_WIDTH (f) == 0) + bitmap = ZV_LINE_BITMAP; else - XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background); - XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - face->gc, - right, - WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, - row->y)), - FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f), - row->visible_height); - if (!face->stipple) - XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground); - } + bitmap = NO_FRINGE_BITMAP; - /* Draw the right bitmap. */ - if (bitmap != NO_BITMAP) - x_draw_bitmap (w, row, bitmap); + x_draw_fringe_bitmap (w, row, bitmap, 0); + } } @@ -1111,7 +1153,8 @@ static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *, XChar2b *, int *)); static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int, - int, XChar2b *, int)); + int, XChar2b *, int, + int)); static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *)); static void x_encode_char P_ ((int, XChar2b *, struct font_info *)); static void x_append_glyph P_ ((struct it *)); @@ -1252,15 +1295,17 @@ x_encode_char (c, char2b, font_info) /* Get face and two-byte form of character C in face FACE_ID on frame F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero - means we want to display multibyte text. Value is a pointer to a - realized face that is ready for display. */ + means we want to display multibyte text. DISPLAY_P non-zero means + make sure that X resources for the face returned are allocated. + Value is a pointer to a realized face that is ready for display if + DISPLAY_P is non-zero. */ static INLINE struct face * -x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p) +x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p, display_p) struct frame *f; int c, face_id; XChar2b *char2b; - int multibyte_p; + int multibyte_p, display_p; { struct face *face = FACE_FROM_ID (f, face_id); @@ -1302,8 +1347,11 @@ x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p) } /* Make sure X resources of the face are allocated. */ - xassert (face != NULL); - PREPARE_FACE_FOR_DISPLAY (f, face); + if (display_p) + { + xassert (face != NULL); + PREPARE_FACE_FOR_DISPLAY (f, face); + } return face; } @@ -1595,7 +1643,7 @@ x_append_stretch_glyph (it, object, width, height, ascent) 4. `:height HEIGHT' specifies that the height of the stretch produced should be HEIGHT, measured in canonical character units. - 5. `:relative-height FACTOR' specifies that the height of the the + 5. `:relative-height FACTOR' specifies that the height of the stretch should be FACTOR times the height of the characters having the glyph property. @@ -1814,7 +1862,7 @@ x_produce_glyphs (it) /* Get font to use. Encode IT->char_to_display. */ x_get_char_face_and_encoding (it->f, it->char_to_display, it->face_id, &char2b, - it->multibyte_p); + it->multibyte_p, 0); font = face->font; /* When no suitable font found, use the default font. */ @@ -2046,7 +2094,7 @@ x_produce_glyphs (it) it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display); face = FACE_FROM_ID (it->f, it->face_id); x_get_char_face_and_encoding (it->f, it->char_to_display, - it->face_id, &char2b, it->multibyte_p); + it->face_id, &char2b, it->multibyte_p, 0); font = face->font; /* When no suitable font found, use the default font. */ @@ -2134,7 +2182,7 @@ x_produce_glyphs (it) face = FACE_FROM_ID (it->f, face_id); x_get_char_face_and_encoding (it->f, ch, face->id, &char2b, - it->multibyte_p); + it->multibyte_p, 0); font = face->font; if (font == NULL) { @@ -3823,6 +3871,10 @@ x_setup_relief_colors (s) 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; @@ -3893,7 +3945,7 @@ x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width, for (i = 0; i < width; ++i) XDrawLine (dpy, window, gc, left_x + i * left_p, bottom_y - i, - right_x + 2 - i * right_p, bottom_y - i); + right_x + 1 - i * right_p, bottom_y - i); /* Right. */ if (right_p) @@ -3963,7 +4015,7 @@ x_draw_glyph_string_box (s) if (s->row->full_width_p && !s->w->pseudo_window_p) { - last_x += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (s->f); + 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); } @@ -3990,7 +4042,7 @@ x_draw_glyph_string_box (s) || (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) @@ -4076,8 +4128,12 @@ x_draw_image_foreground (s) the image. I believe it's looking better if we do nothing here for mouse-face. */ if (s->hl == DRAW_CURSOR) - XDrawRectangle (s->display, s->window, s->gc, x, y, - s->img->width - 1, s->img->height - 1); + { + 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 @@ -4114,7 +4170,7 @@ x_draw_image_relief (s) if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED) { - thick = tool_bar_button_relief > 0 ? tool_bar_button_relief : 3; + thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF; raised_p = s->hl == DRAW_IMAGE_RAISED; } else @@ -4192,8 +4248,12 @@ x_draw_image_foreground_1 (s, pixmap) the image. I believe it's looking better if we do nothing here for mouse-face. */ if (s->hl == DRAW_CURSOR) - XDrawRectangle (s->display, pixmap, s->gc, x, y, - s->img->width - 1, s->img->height - 1); + { + 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 @@ -4812,7 +4872,9 @@ x_set_glyph_string_background_width (s, start, last_x) || 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_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 @@ -4928,7 +4990,7 @@ x_set_glyph_string_background_width (s, start, last_x) 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); \ + this_face_id, char2b + n, 1, 1); \ } \ \ /* Make glyph_strings for each glyph sequence that is drawable by \ @@ -5047,9 +5109,8 @@ x_draw_glyphs (w, x, row, area, start, end, hl, overlaps_p) if (row->full_width_p) { /* X is relative to the left edge of W, without scroll bars - or flag areas. */ + or fringes. */ struct frame *f = XFRAME (w->frame); - /* int width = FRAME_FLAGS_AREA_WIDTH (f); */ int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f); x += window_left_x; @@ -5171,7 +5232,12 @@ x_draw_glyphs (w, x, row, area, start, end, hl, overlaps_p) for (s = head; s; s = s->next) x_draw_glyph_string (s); - if (area == TEXT_AREA) + 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; @@ -5179,14 +5245,15 @@ x_draw_glyphs (w, x, row, area, start, end, hl, overlaps_p) x0 = FRAME_TO_WINDOW_PIXEL_X (w, x0); x1 = FRAME_TO_WINDOW_PIXEL_X (w, x1); - if (!row->full_width_p && XFASTINT (w->left_margin_width) != 0) + 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, x0, x1); + 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. @@ -5276,6 +5343,14 @@ x_write_glyphs (start, len) 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. */ @@ -5408,7 +5483,10 @@ x_clear_end_of_line (to_x) /* Notice if the cursor will be cleared by this operation. */ if (!updated_row->full_width_p) - notice_overwritten_cursor (w, output_cursor.x, -1); + notice_overwritten_cursor (w, updated_area, + output_cursor.x, -1, + updated_row->y, + MATRIX_ROW_BOTTOM_Y (updated_row)); from_x = output_cursor.x; @@ -5715,11 +5793,11 @@ x_scroll_run (w, run) 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 flags areas to the - left and right 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_FLAGS_AREA_WIDTH (f); - x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f); + 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); @@ -5963,7 +6041,7 @@ expose_line (w, row, r) expose_area (w, row, r, TEXT_AREA); if (row->used[RIGHT_MARGIN_AREA]) expose_area (w, row, r, RIGHT_MARGIN_AREA); - x_draw_row_bitmaps (w, row); + x_draw_row_fringe_bitmaps (w, row); } return row->mouse_face_p; @@ -5994,6 +6072,39 @@ x_phys_cursor_in_rect_p (w, r) } +/* 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 @@ -6035,6 +6146,7 @@ expose_window (w, fr) 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)); @@ -6053,7 +6165,8 @@ expose_window (w, fr) else cursor_cleared_p = 0; - /* Find the first row intersecting the rectangle R. */ + /* Update lines intersecting rectangle R. */ + first_overlapping_row = last_overlapping_row = NULL; for (row = w->current_matrix->rows; row->enabled_p; ++row) @@ -6066,6 +6179,13 @@ expose_window (w, fr) || (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; } @@ -6086,6 +6206,10 @@ expose_window (w, fr) 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); @@ -6225,6 +6349,121 @@ x_new_focus_frame (dpyinfo, frame) x_frame_rehighlight (dpyinfo); } +/* Handle FocusIn and FocusOut state changes for FRAME. + If FRAME has focus and there exists more than one frame, puts + an 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 @@ -6393,12 +6632,28 @@ x_x_to_emacs_modifiers (dpyinfo, state) struct x_display_info *dpyinfo; unsigned int state; { + EMACS_UINT mod_meta = meta_modifier; + EMACS_UINT mod_alt = alt_modifier; + EMACS_UINT mod_hyper = hyper_modifier; + EMACS_UINT mod_super = super_modifier; + Lisp_Object tem; + + tem = Fget (Vx_alt_keysym, Qmodifier_value); + if (! EQ (tem, Qnil)) mod_alt = XUINT (tem); + tem = Fget (Vx_meta_keysym, Qmodifier_value); + if (! EQ (tem, Qnil)) mod_meta = XUINT (tem); + tem = Fget (Vx_hyper_keysym, Qmodifier_value); + if (! EQ (tem, Qnil)) mod_hyper = XUINT (tem); + tem = Fget (Vx_super_keysym, Qmodifier_value); + if (! EQ (tem, Qnil)) mod_super = XUINT (tem); + + return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0) - | ((state & ControlMask) ? ctrl_modifier : 0) - | ((state & dpyinfo->meta_mod_mask) ? meta_modifier : 0) - | ((state & dpyinfo->alt_mod_mask) ? alt_modifier : 0) - | ((state & dpyinfo->super_mod_mask) ? super_modifier : 0) - | ((state & dpyinfo->hyper_mod_mask) ? hyper_modifier : 0)); + | ((state & ControlMask) ? ctrl_modifier : 0) + | ((state & dpyinfo->meta_mod_mask) ? mod_meta : 0) + | ((state & dpyinfo->alt_mod_mask) ? mod_alt : 0) + | ((state & dpyinfo->super_mod_mask) ? mod_super : 0) + | ((state & dpyinfo->hyper_mod_mask) ? mod_hyper : 0)); } static unsigned int @@ -6406,12 +6661,29 @@ x_emacs_to_x_modifiers (dpyinfo, state) struct x_display_info *dpyinfo; unsigned int state; { - return ( ((state & alt_modifier) ? dpyinfo->alt_mod_mask : 0) - | ((state & super_modifier) ? dpyinfo->super_mod_mask : 0) - | ((state & hyper_modifier) ? dpyinfo->hyper_mod_mask : 0) - | ((state & shift_modifier) ? ShiftMask : 0) - | ((state & ctrl_modifier) ? ControlMask : 0) - | ((state & meta_modifier) ? dpyinfo->meta_mod_mask : 0)); + EMACS_UINT mod_meta = meta_modifier; + EMACS_UINT mod_alt = alt_modifier; + EMACS_UINT mod_hyper = hyper_modifier; + EMACS_UINT mod_super = super_modifier; + + Lisp_Object tem; + + tem = Fget (Vx_alt_keysym, Qmodifier_value); + if (! EQ (tem, Qnil)) mod_alt = XUINT (tem); + tem = Fget (Vx_meta_keysym, Qmodifier_value); + if (! EQ (tem, Qnil)) mod_meta = XUINT (tem); + tem = Fget (Vx_hyper_keysym, Qmodifier_value); + if (! EQ (tem, Qnil)) mod_hyper = XUINT (tem); + tem = Fget (Vx_super_keysym, Qmodifier_value); + if (! EQ (tem, Qnil)) mod_super = XUINT (tem); + + + return ( ((state & mod_alt) ? dpyinfo->alt_mod_mask : 0) + | ((state & mod_super) ? dpyinfo->super_mod_mask : 0) + | ((state & mod_hyper) ? dpyinfo->hyper_mod_mask : 0) + | ((state & shift_modifier) ? ShiftMask : 0) + | ((state & ctrl_modifier) ? ControlMask : 0) + | ((state & mod_meta) ? dpyinfo->meta_mod_mask : 0)); } /* Convert a keysym to its name. */ @@ -6537,9 +6809,9 @@ construct_mouse_click (result, event, f) XButtonEvent *event; struct frame *f; { - /* Make the event type no_event; we'll change that when we decide + /* Make the event type NO_EVENT; we'll change that when we decide otherwise. */ - result->kind = mouse_click; + result->kind = MOUSE_CLICK_EVENT; result->code = event->button - Button1; result->timestamp = event->time; result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), @@ -6595,11 +6867,6 @@ note_mouse_movement (frame, event) } } -/* This is used for debugging, to turn off note_mouse_highlight. */ - - int disable_mouse_highlight; - - /************************************************************************ Mouse Face @@ -6716,80 +6983,54 @@ frame_to_window_pixel_xy (w, x, y) } -/* Take proper action when mouse has moved to the mode or header line of - window W, x-position X. MODE_LINE_P non-zero means mouse is on the - mode line. X is relative to the start of the text display area of - W, so the width of bitmap areas and scroll bars must be subtracted - to get a position relative to the start of the mode line. */ - +/* Take proper action when mouse has moved to the mode or header line + or marginal area of window W, x-position X and y-position Y. Area + is 1, 3, 6 or 7 for the mode line, header line, left and right + marginal area respectively. X is relative to the start of the text + display area of W, so the width of bitmap areas and scroll bars + must be subtracted to get a position relative to the start of the + mode line. */ + static void -note_mode_line_highlight (w, x, mode_line_p) +note_mode_line_or_margin_highlight (w, x, y, portion) struct window *w; - int x, mode_line_p; + int x, y, portion; { struct frame *f = XFRAME (w->frame); struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); Cursor cursor = dpyinfo->vertical_scroll_bar_cursor; - struct glyph_row *row; + int charpos; + Lisp_Object string, help, map, pos; - if (mode_line_p) - row = MATRIX_MODE_LINE_ROW (w->current_matrix); - else - row = MATRIX_HEADER_LINE_ROW (w->current_matrix); + if (portion == 1 || portion == 3) + string = mode_line_string (w, x, y, portion == 1, &charpos); + else + string = marginal_area_string (w, x, y, portion, &charpos); - if (row->enabled_p) + if (STRINGP (string)) { - struct glyph *glyph, *end; - Lisp_Object help, map; - int x0; - - /* Find the glyph under X. */ - glyph = row->glyphs[TEXT_AREA]; - end = glyph + row->used[TEXT_AREA]; - x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f) - + FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)); + pos = make_number (charpos); - while (glyph < end - && x >= x0 + glyph->pixel_width) + /* If we're on a string with `help-echo' text property, arrange + for the help to be displayed. This is done by setting the + global variable help_echo to the help string. */ + help = Fget_text_property (pos, Qhelp_echo, string); + if (!NILP (help)) { - x0 += glyph->pixel_width; - ++glyph; + help_echo = help; + XSETWINDOW (help_echo_window, w); + help_echo_object = string; + help_echo_pos = charpos; } - if (glyph < end - && STRINGP (glyph->object) - && XSTRING (glyph->object)->intervals - && glyph->charpos >= 0 - && glyph->charpos < XSTRING (glyph->object)->size) - { - /* If we're on a string with `help-echo' text property, - arrange for the help to be displayed. This is done by - setting the global variable help_echo to the help string. */ - help = Fget_text_property (make_number (glyph->charpos), - Qhelp_echo, glyph->object); - if (!NILP (help)) - { - help_echo = help; - XSETWINDOW (help_echo_window, w); - help_echo_object = glyph->object; - help_echo_pos = glyph->charpos; - } - - /* Change the mouse pointer according to what is under X/Y. */ - map = Fget_text_property (make_number (glyph->charpos), - Qlocal_map, glyph->object); - if (KEYMAPP (map)) - cursor = f->output_data.x->nontext_cursor; - else - { - map = Fget_text_property (make_number (glyph->charpos), - Qkeymap, glyph->object); - if (KEYMAPP (map)) - cursor = f->output_data.x->nontext_cursor; - } - } + /* Change the mouse pointer according to what is under X/Y. */ + map = Fget_text_property (pos, Qlocal_map, string); + if (!KEYMAPP (map)) + map = Fget_text_property (pos, Qkeymap, string); + if (KEYMAPP (map)) + cursor = f->output_data.x->nontext_cursor; } - + XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor); } @@ -6817,7 +7058,7 @@ note_mouse_highlight (f, x, y) return; #endif - if (disable_mouse_highlight + if (NILP (Vmouse_highlight) || !f->glyphs_initialized_p) return; @@ -6857,10 +7098,10 @@ note_mouse_highlight (f, x, y) return; } - /* Mouse is on the mode or header line? */ - if (portion == 1 || portion == 3) + /* Mouse is on the mode, header line or margin? */ + if (portion == 1 || portion == 3 || portion == 6 || portion == 7) { - note_mode_line_highlight (w, x, portion == 1); + note_mode_line_or_margin_highlight (w, x, y, portion); return; } @@ -7076,7 +7317,7 @@ note_mouse_highlight (f, x, y) if (NILP (b)) b = make_number (0); if (NILP (e)) - e = make_number (XSTRING (object)->size - 1); + e = make_number (SCHARS (object) - 1); fast_find_string_pos (w, XINT (b), object, &dpyinfo->mouse_face_beg_col, &dpyinfo->mouse_face_beg_row, @@ -7112,7 +7353,7 @@ note_mouse_highlight (f, x, y) { Lisp_Object before = Foverlay_start (overlay); Lisp_Object after = Foverlay_end (overlay); - Lisp_Object ignore; + int ignore; /* Note that we might not be able to find position BEFORE in the glyph matrix if the overlay is @@ -7174,7 +7415,7 @@ note_mouse_highlight (f, x, y) /* Try text properties. */ if (STRINGP (object) && charpos >= 0 - && charpos < XSTRING (object)->size) + && charpos < SCHARS (object)) { help = Fget_text_property (make_number (charpos), Qhelp_echo, object); @@ -7297,7 +7538,7 @@ x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx) /* Handle mouse button event on the tool-bar of frame F, at - frame-relative coordinates X/Y. EVENT_TYPE is either ButtionPress + frame-relative coordinates X/Y. EVENT_TYPE is either ButtonPress or ButtonRelase. */ static void @@ -7441,7 +7682,7 @@ note_tool_bar_highlight (f, x, y) set_help_echo: - /* Set help_echo to a help string.to display for this tool-bar item. + /* Set help_echo to a help string to display for this tool-bar item. XTread_socket does the rest. */ help_echo_object = help_echo_window = Qnil; help_echo_pos = -1; @@ -7627,9 +7868,9 @@ fast_find_position (w, pos, hpos, vpos, x, y, stop) #endif /* not 0 */ -/* Find the position of the the glyph for position POS in OBJECT in - window W's current matrix, and return in *X/*Y the pixel - coordinates, and return in *HPOS/*VPOS the column/row of the glyph. +/* Find the position of the glyph for position POS in OBJECT in + window W's current matrix, and return in *X, *Y the pixel + coordinates, and return in *HPOS, *VPOS the column/row of the glyph. RIGHT_P non-zero means return the position of the right edge of the glyph, RIGHT_P zero means return the left edge position. @@ -7719,82 +7960,61 @@ show_mouse_face (dpyinfo, draw) { struct window *w = XWINDOW (dpyinfo->mouse_face_window); struct frame *f = XFRAME (WINDOW_FRAME (w)); - int i; - int cursor_off_p = 0; - struct cursor_pos saved_cursor; - - saved_cursor = output_cursor; - - /* If window is in the process of being destroyed, don't bother - to do anything. */ - if (w->current_matrix == NULL) - goto set_x_cursor; - - /* Recognize when we are called to operate on rows that don't exist - anymore. This can happen when a window is split. */ - if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows) - goto set_x_cursor; - - set_output_cursor (&w->phys_cursor); - /* Note that mouse_face_beg_row etc. are window relative. */ - for (i = dpyinfo->mouse_face_beg_row; - i <= dpyinfo->mouse_face_end_row; - i++) + if (/* If window is in the process of being destroyed, don't bother + to do anything. */ + w->current_matrix != NULL + /* Don't update mouse highlight if hidden */ + && (draw != DRAW_MOUSE_FACE || !dpyinfo->mouse_face_hidden) + /* Recognize when we are called to operate on rows that don't exist + anymore. This can happen when a window is split. */ + && dpyinfo->mouse_face_end_row < w->current_matrix->nrows) { - int start_hpos, end_hpos, start_x; - struct glyph_row *row = MATRIX_ROW (w->current_matrix, i); + int phys_cursor_on_p = w->phys_cursor_on_p; + struct glyph_row *row, *first, *last; - /* Don't do anything if row doesn't have valid contents. */ - if (!row->enabled_p) - continue; - - /* For all but the first row, the highlight starts at column 0. */ - if (i == dpyinfo->mouse_face_beg_row) - { - start_hpos = dpyinfo->mouse_face_beg_col; - start_x = dpyinfo->mouse_face_beg_x; - } - else + first = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_beg_row); + last = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_end_row); + + for (row = first; row <= last && row->enabled_p; ++row) { - start_hpos = 0; - start_x = 0; - } + int start_hpos, end_hpos, start_x; - if (i == dpyinfo->mouse_face_end_row) - end_hpos = dpyinfo->mouse_face_end_col; - else - end_hpos = row->used[TEXT_AREA]; + /* For all but the first row, the highlight starts at column 0. */ + if (row == first) + { + start_hpos = dpyinfo->mouse_face_beg_col; + start_x = dpyinfo->mouse_face_beg_x; + } + else + { + start_hpos = 0; + start_x = 0; + } - /* If the cursor's in the text we are about to rewrite, turn the - cursor off. */ - if (!w->pseudo_window_p - && i == output_cursor.vpos - && output_cursor.hpos >= start_hpos - 1 - && output_cursor.hpos <= end_hpos) - { - x_update_window_cursor (w, 0); - cursor_off_p = 1; - } + if (row == last) + end_hpos = dpyinfo->mouse_face_end_col; + else + end_hpos = row->used[TEXT_AREA]; - if (end_hpos > start_hpos) - { - x_draw_glyphs (w, start_x, row, TEXT_AREA, - start_hpos, end_hpos, draw, 0); - row->mouse_face_p = draw == DRAW_MOUSE_FACE || DRAW_IMAGE_RAISED; - } - } + if (end_hpos > start_hpos) + { + x_draw_glyphs (w, start_x, row, TEXT_AREA, + start_hpos, end_hpos, draw, 0); - /* If we turned the cursor off, turn it back on. */ - if (cursor_off_p) - x_display_cursor (w, 1, - output_cursor.hpos, output_cursor.vpos, - output_cursor.x, output_cursor.y); + row->mouse_face_p + = draw == DRAW_MOUSE_FACE || draw == DRAW_IMAGE_RAISED; + } + } - output_cursor = saved_cursor; + /* When we've written over the cursor, arrange for it to + be displayed again. */ + if (phys_cursor_on_p && !w->phys_cursor_on_p) + x_display_cursor (w, 1, + w->phys_cursor.hpos, w->phys_cursor.vpos, + w->phys_cursor.x, w->phys_cursor.y); + } - set_x_cursor: - /* Change the mouse cursor. */ if (draw == DRAW_NORMAL_TEXT) XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), @@ -8278,7 +8498,7 @@ static Boolean xaw3d_pick_top; /* Action hook installed via XtAppAddActionHook when toolkit scroll bars are used.. The hook is responsible for detecting when the user ends an interaction with the scroll bar, and generates - a `end-scroll' scroll_bar_click' event if so. */ + a `end-scroll' SCROLL_BAR_CLICK_EVENT' event if so. */ static void xt_action_hook (widget, client_data, action_name, event, params, @@ -8408,7 +8628,7 @@ x_scroll_bar_to_input_event (event, ievent) XSETWINDOW (window, w); f = XFRAME (w->frame); - ievent->kind = scroll_bar_click; + ievent->kind = SCROLL_BAR_CLICK_EVENT; ievent->frame_or_window = window; ievent->arg = Qnil; ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f)); @@ -8431,7 +8651,7 @@ x_scroll_bar_to_input_event (event, ievent) /* Scroll bar callback for Motif scroll bars. WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the scroll_bar structure. - CALL_DATA is a pointer a a XmScrollBarCallbackStruct. */ + CALL_DATA is a pointer to a XmScrollBarCallbackStruct. */ static void xm_scroll_callback (widget, client_data, call_data) @@ -8485,31 +8705,10 @@ xm_scroll_callback (widget, client_data, call_data) XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL); UNBLOCK_INPUT; - /* At the max position of the scroll bar, do a line-wise - movement. Without doing anything, we would be called with - the same cs->value again and again. If we want to make - sure that we can reach the end of the buffer, we have to do - something. - - Implementation note: setting bar->dragging always to - cs->value gives a smoother movement at the max position. - Setting it to nil when doing line-wise movement gives - a better slider behavior. */ - - if (cs->value + slider_size == XM_SB_MAX - || (dragging_down_p - && last_scroll_bar_part == scroll_bar_down_arrow)) - { - part = scroll_bar_down_arrow; - bar->dragging = Qnil; - } - else - { - whole = XM_SB_RANGE; - portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size); - part = scroll_bar_handle; - bar->dragging = make_number (cs->value); - } + whole = XM_SB_RANGE - slider_size; + portion = min (cs->value - XM_SB_MIN, whole); + part = scroll_bar_handle; + bar->dragging = make_number (cs->value); } break; @@ -8786,7 +8985,7 @@ x_create_toolkit_scroll_bar (f, bar) #endif /* !USE_MOTIF */ - /* Install an action hook that let's us detect when the user + /* Install an action hook that lets us detect when the user finishes interacting with a scroll bar. */ if (action_hook_id == 0) action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0); @@ -8812,7 +9011,27 @@ x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole) Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar); float top, shown; - if (whole == 0) + BLOCK_INPUT; + +#ifdef USE_MOTIF + + /* We use an estimate of 30 chars per line rather than the real + `portion' value. This has the disadvantage that the thumb size + is not very representative, but it makes our life a lot easier. + Otherwise, we have to constantly adjust the thumb size, which + we can't always do quickly enough: while dragging, the size of + the thumb might prevent the user from dragging the thumb all the + way to the end. but Motif and some versions of Xaw3d don't allow + updating the thumb size while dragging. Also, even if we can update + its size, the update will often happen too late. + If you don't believe it, check out revision 1.650 of xterm.c to see + what hoops we were going through and the still poor behavior we got. */ + portion = XFASTINT (XWINDOW (bar->window)->height) * 30; + /* When the thumb is at the bottom, position == whole. + So we need to increase `whole' to make space for the thumb. */ + whole += portion; + + if (whole <= 0) top = 0, shown = 1; else { @@ -8820,45 +9039,34 @@ x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole) shown = (float) portion / whole; } - BLOCK_INPUT; - -#ifdef USE_MOTIF - { - int size, value; - - /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX - is the scroll bar's maximum and MIN is the scroll bar's minimum - value. */ - size = shown * XM_SB_RANGE; - size = min (size, XM_SB_RANGE); - size = max (size, 1); + if (NILP (bar->dragging)) + { + int size, value; - /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */ - value = top * XM_SB_RANGE; - value = min (value, XM_SB_MAX - size); - value = max (value, XM_SB_MIN); + /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX + is the scroll bar's maximum and MIN is the scroll bar's minimum + value. */ + size = shown * XM_SB_RANGE; + size = min (size, XM_SB_RANGE); + size = max (size, 1); - if (NILP (bar->dragging)) + /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */ + value = top * XM_SB_RANGE; + value = min (value, XM_SB_MAX - size); + value = max (value, XM_SB_MIN); + XmScrollBarSetValues (widget, value, size, 0, 0, False); - else if (last_scroll_bar_part == scroll_bar_down_arrow) - /* This has the negative side effect that the slider value is - not what it would be if we scrolled here using line-wise or - page-wise movement. */ - XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False); - else - { - /* If currently dragging, only update the slider size. - This reduces flicker effects. */ - int old_value, old_size, increment, page_increment; - - XmScrollBarGetValues (widget, &old_value, &old_size, - &increment, &page_increment); - XmScrollBarSetValues (widget, old_value, - min (size, XM_SB_RANGE - old_value), - 0, 0, False); - } - } + } #else /* !USE_MOTIF i.e. use Xaw */ + + if (whole == 0) + top = 0, shown = 1; + else + { + top = (float) position / whole; + shown = (float) portion / whole; + } + { float old_top, old_shown; Dimension height; @@ -8927,7 +9135,7 @@ x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole) /* Create a scroll bar and return the scroll bar vector for it. W is the Emacs window on which to create the scroll bar. TOP, LEFT, - WIDTH and HEIGHT are.the pixel coordinates and dimensions of the + WIDTH and HEIGHT are the pixel coordinates and dimensions of the scroll bar. */ static struct scroll_bar * @@ -8963,9 +9171,10 @@ x_scroll_bar_create (w, top, left, width, height) /* Clear the area of W that will serve as a scroll bar. This is for the case that a window has been split horizontally. In this case, no clear_frame is generated to reduce flickering. */ - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - left, top, width, - window_box_height (w), False); + if (width > 0 && height > 0) + x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + left, top, width, + window_box_height (w), False); window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), /* Position and size of scroll bar. */ @@ -9208,7 +9417,7 @@ XTset_vertical_scroll_bar (w, portion, whole, position) /* Does the scroll bar exist yet? */ if (NILP (w->vertical_scroll_bar)) { - if (width && height) + if (width > 0 && height > 0) { BLOCK_INPUT; x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), @@ -9240,7 +9449,7 @@ XTset_vertical_scroll_bar (w, portion, whole, position) /* Since toolkit scroll bars are smaller than the space reserved for them on the frame, we have to clear "under" them. */ - if (width && height) + if (width > 0 && height > 0) x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), left, top, width, height, False); @@ -9268,16 +9477,22 @@ XTset_vertical_scroll_bar (w, portion, whole, position) } /* Clear areas not covered by the scroll bar because it's not as - wide as the area reserved for it . This makes sure a + wide as the area reserved for it. This makes sure a previous mode line display is cleared after C-x 2 C-x 1, for example. */ { int area_width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f); int rest = area_width - sb_width; - if (rest > 0) - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - left + area_width - rest, top, - rest, max (height, 1), False); + if (rest > 0 && height > 0) + { + if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)) + x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + left + area_width - rest, top, + rest, height, False); + else + x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + left, top, rest, height, False); + } } /* Move/size the scroll bar window. */ @@ -9471,7 +9686,7 @@ x_scroll_bar_expose (bar, event) } /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind - is set to something other than no_event, it is enqueued. + is set to something other than NO_EVENT, it is enqueued. This may be called from a signal handler, so we have to ignore GC mark bits. */ @@ -9487,7 +9702,7 @@ x_scroll_bar_handle_click (bar, event, emacs_event) if (! GC_WINDOWP (bar->window)) abort (); - emacs_event->kind = scroll_bar_click; + emacs_event->kind = SCROLL_BAR_CLICK_EVENT; emacs_event->code = event->xbutton.button - Button1; emacs_event->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO @@ -9809,11 +10024,13 @@ x_stop_queuing_selection_requests (display) /* The main X event-reading loop - XTread_socket. */ +#if 0 /* Time stamp of enter window event. This is only used by XTread_socket, but we have to put it out here, since static variables within functions sometimes don't work. */ static Time enter_timestamp; +#endif /* This holds the state XLookupString needs to implement dead keys and other tricks known as "compose processing". _X Window System_ @@ -9821,7 +10038,7 @@ static Time enter_timestamp; me that letting the compiler initialize it to zeros will work okay. This must be defined outside of XTread_socket, for the same reasons - given for enter_time stamp, above. */ + given for enter_timestamp, above. */ static XComposeStatus compose_status; @@ -9852,7 +10069,7 @@ static struct x_display_info *next_noop_dpyinfo; bcopy (&event, f->output_data.x->saved_menu_event, size); \ if (numchars >= 1) \ { \ - bufp->kind = menu_bar_activate_event; \ + bufp->kind = MENU_BAR_ACTIVATE_EVENT; \ XSETFRAME (bufp->frame_or_window, f); \ bufp->arg = Qnil; \ bufp++; \ @@ -9876,7 +10093,7 @@ static struct x_display_info *next_noop_dpyinfo; EXPECTED is nonzero if the caller knows input is available. */ -int +static int XTread_socket (sd, bufp, numchars, expected) register int sd; /* register */ struct input_event *bufp; @@ -9908,18 +10125,6 @@ XTread_socket (sd, bufp, numchars, expected) ++handling_signal; - /* The input should be decoded if it is from XIM. Currently the - locale of XIM is the same as that of the system. So, we can use - Vlocale_coding_system which is initialized properly at Emacs - startup time. */ - setup_coding_system (Vlocale_coding_system, &coding); - coding.src_multibyte = 0; - coding.dst_multibyte = 1; - /* The input is converted to events, thus we can't handle - composition. Anyway, there's no XIM that gives us composition - information. */ - coding.composing = COMPOSITION_DISABLED; - /* Find the display we are supposed to read input for. It's the one communicating on descriptor SD. */ for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) @@ -9958,6 +10163,12 @@ XTread_socket (sd, bufp, numchars, expected) x_io_error_quitter (dpyinfo->display); } +#ifdef HAVE_X_SM + BLOCK_INPUT; + count += x_session_check_input (bufp, &numchars); + UNBLOCK_INPUT; +#endif + while (XPending (dpyinfo->display)) { XNextEvent (dpyinfo->display, &event); @@ -10040,11 +10251,17 @@ XTread_socket (sd, bufp, numchars, expected) the session manager, who's looking for such a PropertyNotify. Can restart processing when a keyboard or mouse event arrives. */ - if (numchars > 0) + /* If we have a session manager, don't set this. + KDE will then start two Emacsen, one for the + session manager and one for this. */ + if (numchars > 0 +#ifdef HAVE_X_SM + && ! x_session_have_connection () +#endif + ) { f = x_top_window_to_frame (dpyinfo, event.xclient.window); - /* This is just so we only give real data once for a single Emacs process. */ if (f == SELECTED_FRAME ()) @@ -10069,7 +10286,7 @@ XTread_socket (sd, bufp, numchars, expected) if (numchars == 0) abort (); - bufp->kind = delete_window_event; + bufp->kind = DELETE_WINDOW_EVENT; XSETFRAME (bufp->frame_or_window, f); bufp->arg = Qnil; bufp++; @@ -10159,7 +10376,7 @@ XTread_socket (sd, bufp, numchars, expected) if (numchars == 0) abort (); - bufp->kind = selection_clear_event; + bufp->kind = SELECTION_CLEAR_EVENT; SELECTION_EVENT_DISPLAY (bufp) = eventp->display; SELECTION_EVENT_SELECTION (bufp) = eventp->selection; SELECTION_EVENT_TIME (bufp) = eventp->time; @@ -10188,7 +10405,7 @@ XTread_socket (sd, bufp, numchars, expected) if (numchars == 0) abort (); - bufp->kind = selection_request_event; + bufp->kind = SELECTION_REQUEST_EVENT; SELECTION_EVENT_DISPLAY (bufp) = eventp->display; SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor; SELECTION_EVENT_SELECTION (bufp) = eventp->selection; @@ -10232,6 +10449,8 @@ XTread_socket (sd, bufp, numchars, expected) f = x_window_to_frame (dpyinfo, event.xexpose.window); if (f) { + x_check_fullscreen (f); + if (f->async_visible == 0) { f->async_visible = 1; @@ -10326,7 +10545,7 @@ XTread_socket (sd, bufp, numchars, expected) { f->async_iconified = 1; - bufp->kind = iconify_event; + bufp->kind = ICONIFY_EVENT; XSETFRAME (bufp->frame_or_window, f); bufp->arg = Qnil; bufp++; @@ -10358,7 +10577,7 @@ XTread_socket (sd, bufp, numchars, expected) if (f->iconified) { - bufp->kind = deiconify_event; + bufp->kind = DEICONIFY_EVENT; XSETFRAME (bufp->frame_or_window, f); bufp->arg = Qnil; bufp++; @@ -10375,8 +10594,19 @@ XTread_socket (sd, bufp, numchars, expected) goto OTHER; case KeyPress: + + /* Dispatch KeyPress events when in menu. */ + if (popup_activated_flag) + goto OTHER; + f = x_any_window_to_frame (dpyinfo, event.xkey.window); + if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)) + { + dpyinfo->mouse_face_hidden = 1; + clear_mouse_face (dpyinfo); + } + #if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS if (f == 0) { @@ -10404,12 +10634,13 @@ XTread_socket (sd, bufp, numchars, expected) status_return even if the input is too long to fit in 81 bytes. So, we must prepare sufficient bytes for copy_buffer. 513 bytes (256 chars for - two-byte character set) seems to be a faily good + two-byte character set) seems to be a fairly good approximation. -- 2000.8.10 handa@etl.go.jp */ unsigned char copy_buffer[513]; unsigned char *copy_bufptr = copy_buffer; int copy_bufsiz = sizeof (copy_buffer); int modifiers; + Lisp_Object coding_system = Qlatin_1; event.xkey.state |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f), @@ -10439,6 +10670,7 @@ XTread_socket (sd, bufp, numchars, expected) { Status status_return; + coding_system = Vlocale_coding_system; nbytes = XmbLookupString (FRAME_XIC (f), &event.xkey, copy_bufptr, copy_bufsiz, &keysym, @@ -10452,6 +10684,27 @@ XTread_socket (sd, bufp, numchars, expected) copy_bufsiz, &keysym, &status_return); } +/* Xutf8LookupString is a new but already deprecated interface. -stef */ +#if 0 && defined X_HAVE_UTF8_STRING + else if (status_return == XLookupKeySym) + { /* Try again but with utf-8. */ + coding_system = Qutf_8; + nbytes = Xutf8LookupString (FRAME_XIC (f), + &event.xkey, copy_bufptr, + copy_bufsiz, &keysym, + &status_return); + if (status_return == XBufferOverflow) + { + copy_bufsiz = nbytes + 1; + copy_bufptr = (char *) alloca (copy_bufsiz); + nbytes = Xutf8LookupString (FRAME_XIC (f), + &event.xkey, + copy_bufptr, + copy_bufsiz, &keysym, + &status_return); + } + } +#endif if (status_return == XLookupNone) break; @@ -10547,12 +10800,20 @@ XTread_socket (sd, bufp, numchars, expected) || ((unsigned)(orig_keysym) == XK_Num_Lock) #endif #endif /* not HAVE_X11R5 */ + /* The symbols from XK_ISO_Lock to + XK_ISO_Last_Group_Lock doesn't have real + modifiers but should be treated similarly + to Mode_switch by Emacs. */ +#if defined XK_ISO_Lock && defined XK_ISO_Last_Group_Lock + || ((unsigned)(orig_keysym) >= XK_ISO_Lock + && (unsigned)(orig_keysym) <= XK_ISO_Last_Group_Lock) +#endif )) { if (temp_index == sizeof temp_buffer / sizeof (short)) temp_index = 0; temp_buffer[temp_index++] = keysym; - bufp->kind = non_ascii_keystroke; + bufp->kind = NON_ASCII_KEYSTROKE_EVENT; bufp->code = keysym; XSETFRAME (bufp->frame_or_window, f); bufp->arg = Qnil; @@ -10570,6 +10831,17 @@ XTread_socket (sd, bufp, numchars, expected) register int c; int nchars, len; + /* The input should be decoded with `coding_system' + which depends on which X*LookupString function + we used just above and the locale. */ + setup_coding_system (coding_system, &coding); + coding.src_multibyte = 0; + coding.dst_multibyte = 1; + /* The input is converted to events, thus we can't + handle composition. Anyway, there's no XIM that + gives us composition information. */ + coding.composing = COMPOSITION_DISABLED; + for (i = 0; i < nbytes; i++) { if (temp_index == (sizeof temp_buffer @@ -10578,41 +10850,39 @@ XTread_socket (sd, bufp, numchars, expected) temp_buffer[temp_index++] = copy_bufptr[i]; } - if (/* If the event is not from XIM, */ - event.xkey.keycode != 0 - /* or the current locale doesn't request - decoding of the intup data, ... */ - || coding.type == coding_type_raw_text - || coding.type == coding_type_no_conversion) - { - /* ... we can use the input data as is. */ - nchars = nbytes; - } - else - { - /* We have to decode the input data. */ - int require; - unsigned char *p; - - require = decoding_buffer_size (&coding, nbytes); - p = (unsigned char *) alloca (require); - coding.mode |= CODING_MODE_LAST_BLOCK; - decode_coding (&coding, copy_bufptr, p, - nbytes, require); - nbytes = coding.produced; - nchars = coding.produced_char; - copy_bufptr = p; - } + { + /* Decode the input data. */ + int require; + unsigned char *p; + + require = decoding_buffer_size (&coding, nbytes); + p = (unsigned char *) alloca (require); + coding.mode |= CODING_MODE_LAST_BLOCK; + /* We explicitely disable composition + handling because key data should + not contain any composition + sequence. */ + coding.composing = COMPOSITION_DISABLED; + decode_coding (&coding, copy_bufptr, p, + nbytes, require); + nbytes = coding.produced; + nchars = coding.produced_char; + copy_bufptr = p; + } /* Convert the input data to a sequence of character events. */ for (i = 0; i < nbytes; i += len) { - c = STRING_CHAR_AND_LENGTH (copy_bufptr + i, - nbytes - i, len); + if (nchars == nbytes) + c = copy_bufptr[i], len = 1; + else + c = STRING_CHAR_AND_LENGTH (copy_bufptr + i, + nbytes - i, len); + bufp->kind = (SINGLE_BYTE_CHAR_P (c) - ? ascii_keystroke - : multibyte_char_keystroke); + ? ASCII_KEYSTROKE_EVENT + : MULTIBYTE_CHAR_KEYSTROKE_EVENT); bufp->code = c; XSETFRAME (bufp->frame_or_window, f); bufp->arg = Qnil; @@ -10654,17 +10924,19 @@ XTread_socket (sd, bufp, numchars, expected) goto OTHER; #endif - /* Here's a possible interpretation of the whole - FocusIn-EnterNotify FocusOut-LeaveNotify mess. If - you get a FocusIn event, you have to get a FocusOut - event before you relinquish the focus. If you - haven't received a FocusIn event, then a mere - LeaveNotify is enough to free you. */ - case EnterNotify: { + int n; + + n = x_detect_focus_change (dpyinfo, &event, bufp, numchars); + if (n > 0) + { + bufp += n, count += n, numchars -= n; + } + f = x_any_window_to_frame (dpyinfo, event.xcrossing.window); +#if 0 if (event.xcrossing.focus) { /* Avoid nasty pop/raise loops. */ @@ -10678,7 +10950,8 @@ XTread_socket (sd, bufp, numchars, expected) } else if (f == dpyinfo->x_focus_frame) x_new_focus_frame (dpyinfo, 0); - +#endif + /* EnterNotify counts as mouse movement, so update things that depend on mouse position. */ if (f && !f->output_data.x->hourglass_p) @@ -10687,34 +10960,29 @@ XTread_socket (sd, bufp, numchars, expected) } case FocusIn: - f = x_any_window_to_frame (dpyinfo, event.xfocus.window); - if (event.xfocus.detail != NotifyPointer) - dpyinfo->x_focus_event_frame = f; - if (f) - { - x_new_focus_frame (dpyinfo, f); + { + int n; - /* Don't stop displaying the initial startup message - for a switch-frame event we don't need. */ - if (GC_NILP (Vterminal_frame) - && GC_CONSP (Vframe_list) - && !GC_NILP (XCDR (Vframe_list))) - { - bufp->kind = FOCUS_IN_EVENT; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - ++bufp, ++count, --numchars; - } - } - -#ifdef HAVE_X_I18N - if (f && FRAME_XIC (f)) - XSetICFocus (FRAME_XIC (f)); -#endif + n = x_detect_focus_change (dpyinfo, &event, bufp, numchars); + if (n > 0) + { + bufp += n, count += n, numchars -= n; + } + } goto OTHER; case LeaveNotify: + { + int n; + + n = x_detect_focus_change (dpyinfo, &event, bufp, numchars); + if (n > 0) + { + bufp += n, count += n, numchars -= n; + } + } + f = x_top_window_to_frame (dpyinfo, event.xcrossing.window); if (f) { @@ -10742,30 +11010,19 @@ XTread_socket (sd, bufp, numchars, expected) bufp += n, count += n, numchars -= n; } - if (event.xcrossing.focus) - x_mouse_leave (dpyinfo); - else - { - if (f == dpyinfo->x_focus_event_frame) - dpyinfo->x_focus_event_frame = 0; - if (f == dpyinfo->x_focus_frame) - x_new_focus_frame (dpyinfo, 0); - } } goto OTHER; case FocusOut: - f = x_any_window_to_frame (dpyinfo, event.xfocus.window); - if (event.xfocus.detail != NotifyPointer - && f == dpyinfo->x_focus_event_frame) - dpyinfo->x_focus_event_frame = 0; - if (f && f == dpyinfo->x_focus_frame) - x_new_focus_frame (dpyinfo, 0); + { + int n; -#ifdef HAVE_X_I18N - if (f && FRAME_XIC (f)) - XUnsetICFocus (FRAME_XIC (f)); -#endif + n = x_detect_focus_change (dpyinfo, &event, bufp, numchars); + if (n > 0) + { + bufp += n, count += n, numchars -= n; + } + } goto OTHER; @@ -10781,8 +11038,43 @@ XTread_socket (sd, bufp, numchars, expected) else f = x_window_to_frame (dpyinfo, event.xmotion.window); + if (dpyinfo->mouse_face_hidden) + { + dpyinfo->mouse_face_hidden = 0; + clear_mouse_face (dpyinfo); + } + if (f) - note_mouse_movement (f, &event.xmotion); + { + + /* Generate SELECT_WINDOW_EVENTs when needed. */ + if (mouse_autoselect_window) + { + Lisp_Object window; + int area; + + window = window_from_coordinates (f, + event.xmotion.x, event.xmotion.y, + &area, 0); + + /* Window will be selected only when it is not selected now and + last mouse movement event was not in it. Minibuffer window + will be selected iff it is active. */ + if (WINDOWP(window) + && !EQ (window, last_window) + && !EQ (window, selected_window) + && numchars > 0) + { + bufp->kind = SELECT_WINDOW_EVENT; + bufp->frame_or_window = window; + bufp->arg = Qnil; + ++bufp, ++count, --numchars; + } + + last_window=window; + } + note_mouse_movement (f, &event.xmotion); + } else { #ifndef USE_TOOLKIT_SCROLL_BARS @@ -10826,8 +11118,17 @@ XTread_socket (sd, bufp, numchars, expected) if (f) { #ifndef USE_X_TOOLKIT + /* If there is a pending resize for fullscreen, don't + do this one, the right one will come later. + The toolkit version doesn't seem to need this, but we + need to reset it below. */ + int dont_resize = + ((f->output_data.x->want_fullscreen & FULLSCREEN_WAIT) + && FRAME_NEW_WIDTH (f) != 0); int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height); int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width); + if (dont_resize) + goto OTHER; /* In the toolkit version, change_frame_size is called by the code that handles resizing @@ -10855,6 +11156,10 @@ XTread_socket (sd, bufp, numchars, expected) x_real_positions (f, &f->output_data.x->left_pos, &f->output_data.x->top_pos); + x_check_fullscreen_move(f); + if (f->output_data.x->want_fullscreen & FULLSCREEN_WAIT) + f->output_data.x->want_fullscreen &= + ~(FULLSCREEN_WAIT|FULLSCREEN_BOTH); #ifdef HAVE_X_I18N if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea)) xic_set_statusarea (f); @@ -10888,7 +11193,7 @@ XTread_socket (sd, bufp, numchars, expected) struct input_event emacs_event; int tool_bar_p = 0; - emacs_event.kind = no_event; + emacs_event.kind = NO_EVENT; bzero (&compose_status, sizeof (compose_status)); if (dpyinfo->grabbed @@ -10954,7 +11259,7 @@ XTread_socket (sd, bufp, numchars, expected) dpyinfo->grabbed &= ~(1 << event.xbutton.button); } - if (numchars >= 1 && emacs_event.kind != no_event) + if (numchars >= 1 && emacs_event.kind != NO_EVENT) { bcopy (&emacs_event, bufp, sizeof (struct input_event)); bufp++; @@ -11086,23 +11391,49 @@ XTread_socket (sd, bufp, numchars, expected) Text Cursor ***********************************************************************/ -/* Notice if the text cursor of window W has been overwritten by a - drawing operation that outputs N glyphs starting at START_X and - ending at END_X in the line given by output_cursor.vpos. - Coordinates are area-relative. END_X < 0 means means all the rest - of the line after START_X has been written. */ +/* Notice when the text cursor of window W has been completely + overwritten by a drawing operation that outputs glyphs in AREA + starting at X0 and ending at X1 in the line starting at Y0 and + ending at Y1. X coordinates are area-relative. X1 < 0 means all + the rest of the line after X0 has been written. Y coordinates + are window-relative. */ static void -notice_overwritten_cursor (w, start_x, end_x) +notice_overwritten_cursor (w, area, x0, x1, y0, y1) struct window *w; - int start_x, end_x; + enum glyph_row_area area; + int x0, y0, x1, y1; { - if (updated_area == TEXT_AREA - && w->phys_cursor_on_p - && output_cursor.vpos == w->phys_cursor.vpos - && start_x <= w->phys_cursor.x - && end_x > w->phys_cursor.x) - w->phys_cursor_on_p = 0; + if (area == TEXT_AREA && w->phys_cursor_on_p) + { + int cx0 = w->phys_cursor.x; + int cx1 = cx0 + w->phys_cursor_width; + int cy0 = w->phys_cursor.y; + int cy1 = cy0 + w->phys_cursor_height; + + if (x0 <= cx0 && (x1 < 0 || x1 >= cx1)) + { + /* The cursor image will be completely removed from the + screen if the output area intersects the cursor area in + y-direction. When we draw in [y0 y1[, and some part of + the cursor is at y < y0, that part must have been drawn + before. When scrolling, the cursor is erased before + actually scrolling, so we don't come here. When not + scrolling, the rows above the old cursor row must have + changed, and in this case these rows must have written + over the cursor image. + + Likewise if part of the cursor is below y1, with the + exception of the cursor being in the first blank row at + the buffer and window end because update_text_area + doesn't draw that row. (Except when it does, but + that's handled in update_text_area.) */ + + if (((y0 >= cy0 && y0 < cy1) || (y1 > cy0 && y1 < cy1)) + && w->current_matrix->rows[w->phys_cursor.vpos].displays_text_p) + w->phys_cursor_on_p = 0; + } + } } @@ -11138,8 +11469,8 @@ x_clip_to_row (w, row, gc, whole_line_p) the rectangle to the left and increase its width. */ if (whole_line_p) { - clip_rect.x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f); - clip_rect.width += FRAME_X_FLAGS_AREA_WIDTH (f); + clip_rect.x -= FRAME_X_LEFT_FRINGE_WIDTH (f); + clip_rect.width += FRAME_X_FRINGE_WIDTH (f); } XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted); @@ -11182,6 +11513,7 @@ x_draw_hollow_cursor (w, row) if (cursor_glyph->type == STRETCH_GLYPH && !x_stretch_cursor_p) wd = min (CANON_X_UNIT (f), wd); + w->phys_cursor_width = wd; /* The foreground of cursor_gc is typically the same as the normal background color, which can cause the cursor box to be invisible. */ @@ -11208,19 +11540,14 @@ x_draw_hollow_cursor (w, row) --gerd. */ static void -x_draw_bar_cursor (w, row, width) +x_draw_bar_cursor (w, row, width, kind) struct window *w; struct glyph_row *row; int width; + enum text_cursor_kinds kind; { struct frame *f = XFRAME (w->frame); struct glyph *cursor_glyph; - GC gc; - int x; - unsigned long mask; - XGCValues xgcv; - Display *dpy; - Window window; /* If cursor is out of bounds, don't draw garbage. This can happen in mini-buffer windows when switching between echo area glyphs @@ -11240,13 +11567,23 @@ x_draw_bar_cursor (w, row, width) } else { - xgcv.background = f->output_data.x->cursor_pixel; - xgcv.foreground = f->output_data.x->cursor_pixel; + Display *dpy = FRAME_X_DISPLAY (f); + Window window = FRAME_X_WINDOW (f); + GC gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc; + unsigned long mask = GCForeground | GCBackground | GCGraphicsExposures; + struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id); + XGCValues xgcv; + + /* If the glyph's background equals the color we normally draw + the bar cursor in, the bar cursor in its normal color is + invisible. Use the glyph's foreground color instead in this + case, on the assumption that the glyph's colors are chosen so + that the glyph is legible. */ + if (face->background == f->output_data.x->cursor_pixel) + xgcv.background = xgcv.foreground = face->foreground; + else + xgcv.background = xgcv.foreground = f->output_data.x->cursor_pixel; xgcv.graphics_exposures = 0; - mask = GCForeground | GCBackground | GCGraphicsExposures; - dpy = FRAME_X_DISPLAY (f); - window = FRAME_X_WINDOW (f); - gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc; if (gc) XChangeGC (dpy, gc, mask, &xgcv); @@ -11258,14 +11595,24 @@ x_draw_bar_cursor (w, row, width) if (width < 0) width = f->output_data.x->cursor_width; + width = min (cursor_glyph->pixel_width, width); - x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); + w->phys_cursor_width = width; x_clip_to_row (w, row, gc, 0); - XFillRectangle (dpy, window, gc, - x, - WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y), - min (cursor_glyph->pixel_width, width), - row->height); + + if (kind == BAR_CURSOR) + XFillRectangle (dpy, window, gc, + WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x), + WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y), + width, row->height); + else + XFillRectangle (dpy, window, gc, + WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x), + WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y + + row->height - width), + cursor_glyph->pixel_width, + width); + XSetClipMask (dpy, gc, None); } } @@ -11299,16 +11646,20 @@ x_draw_phys_cursor_glyph (w, row, hl) if (w->phys_cursor.hpos < row->used[TEXT_AREA]) { int on_p = w->phys_cursor_on_p; + int x1; - x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA, - w->phys_cursor.hpos, w->phys_cursor.hpos + 1, - hl, 0); + x1 = x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA, + w->phys_cursor.hpos, w->phys_cursor.hpos + 1, + hl, 0); w->phys_cursor_on_p = on_p; + if (hl == DRAW_CURSOR) + w->phys_cursor_width = x1 - w->phys_cursor.x; + /* When we erase the cursor, and ROW is overlapped by other rows, make sure that these overlapping parts of other rows are redrawn. */ - if (hl == DRAW_NORMAL_TEXT && row->overlapped_p) + else if (hl == DRAW_NORMAL_TEXT && row->overlapped_p) { if (row > w->current_matrix->rows && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1)) @@ -11354,6 +11705,12 @@ x_erase_phys_cursor (w) if (!cursor_row->enabled_p) goto mark_cursor_off; + /* If row is completely invisible, don't attempt to delete a cursor which + isn't there. This can happen if cursor is at top of a window, and + we switch to a buffer with a header line in that window. */ + if (cursor_row->visible_height <= 0) + goto mark_cursor_off; + /* This can happen when the new row is shorter than the old one. In this case, either x_draw_glyphs or clear_end_of_line should have cleared the cursor. Note that we wouldn't be @@ -11453,6 +11810,7 @@ x_display_and_set_cursor (w, on, hpos, vpos, x, y) struct frame *f = XFRAME (w->frame); int new_cursor_type; int new_cursor_width; + int cursor_off_state = 0; struct glyph_matrix *current_glyphs; struct glyph_row *glyph_row; struct glyph *glyph; @@ -11492,43 +11850,64 @@ x_display_and_set_cursor (w, on, hpos, vpos, x, y) marked off, draw no cursor. In all other cases, we want a hollow box cursor. */ new_cursor_width = -1; + new_cursor_type = -2; + + /* Echo area */ if (cursor_in_echo_area && FRAME_HAS_MINIBUF_P (f) && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window)) { if (w == XWINDOW (echo_area_window)) new_cursor_type = FRAME_DESIRED_CURSOR (f); + else if (NILP (Fbuffer_local_value (Qcursor_in_non_selected_windows, + w->buffer))) + new_cursor_type = NO_CURSOR; else - new_cursor_type = HOLLOW_BOX_CURSOR; + cursor_off_state = 1; } - else + + /* Nonselected window or nonselected frame. */ + else if (f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame + || w != XWINDOW (f->selected_window)) { - if (f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame - || w != XWINDOW (f->selected_window)) - { - extern int cursor_in_non_selected_windows; - - if (MINI_WINDOW_P (w) - || !cursor_in_non_selected_windows - || NILP (XBUFFER (w->buffer)->cursor_type)) - new_cursor_type = NO_CURSOR; - else - new_cursor_type = HOLLOW_BOX_CURSOR; - } - else if (w->cursor_off_p) + if ((MINI_WINDOW_P (w) && minibuf_level == 0) + || NILP (Fbuffer_local_value (Qcursor_in_non_selected_windows, + w->buffer)) + || NILP (XBUFFER (w->buffer)->cursor_type)) new_cursor_type = NO_CURSOR; else - { - struct buffer *b = XBUFFER (w->buffer); + cursor_off_state = 1; + } - if (EQ (b->cursor_type, Qt)) - new_cursor_type = FRAME_DESIRED_CURSOR (f); - else - new_cursor_type = x_specified_cursor_type (b->cursor_type, - &new_cursor_width); + /* If new_cursor_type isn't decided yet, decide it now. */ + if (new_cursor_type == -2) + { + struct buffer *b = XBUFFER (w->buffer); + + if (EQ (b->cursor_type, Qt)) + { + new_cursor_type = FRAME_DESIRED_CURSOR (f); + new_cursor_width = FRAME_CURSOR_WIDTH (f); } + else + new_cursor_type = x_specified_cursor_type (b->cursor_type, + &new_cursor_width); } + /* Dim out or hollow out the cursor, + if it has blinked off or for nonselected windows. */ + if (w->cursor_off_p || cursor_off_state) + { + if (new_cursor_type == FILLED_BOX_CURSOR) + new_cursor_type = HOLLOW_BOX_CURSOR; + else if (new_cursor_type == BAR_CURSOR && new_cursor_width > 1) + new_cursor_width = 1; + else + new_cursor_type = NO_CURSOR; + } + + /* Now new_cursor_type is correct. */ + /* If cursor is currently being shown and we don't want it to be or it is in the wrong place, or the cursor type is not what we want, erase it. */ @@ -11536,12 +11915,17 @@ x_display_and_set_cursor (w, on, hpos, vpos, x, y) && (!on || w->phys_cursor.x != x || w->phys_cursor.y != y - || new_cursor_type != w->phys_cursor_type)) + || new_cursor_type != w->phys_cursor_type + || (new_cursor_type == BAR_CURSOR + && new_cursor_width != w->phys_cursor_width))) x_erase_phys_cursor (w); - /* If the cursor is now invisible and we want it to be visible, - display it. */ - if (on && !w->phys_cursor_on_p) + /* Don't check phys_cursor_on_p here because that flag is only set + to zero in some cases where we know that the cursor has been + completely erased, to avoid the extra work of erasing the cursor + twice. In other words, phys_cursor_on_p can be 1 and the cursor + still not be visible, or it has only been partly erased. */ + if (on) { w->phys_cursor_ascent = glyph_row->ascent; w->phys_cursor_height = glyph_row->height; @@ -11566,10 +11950,15 @@ x_display_and_set_cursor (w, on, hpos, vpos, x, y) break; case BAR_CURSOR: - x_draw_bar_cursor (w, glyph_row, new_cursor_width); + x_draw_bar_cursor (w, glyph_row, new_cursor_width, BAR_CURSOR); + break; + + case HBAR_CURSOR: + x_draw_bar_cursor (w, glyph_row, new_cursor_width, HBAR_CURSOR); break; case NO_CURSOR: + w->phys_cursor_width = 0; break; default: @@ -11761,7 +12150,7 @@ x_error_catcher (display, error) XErrorEvent *error; { XGetErrorText (display, error->error_code, - XSTRING (x_error_message_string)->data, + SDATA (x_error_message_string), X_ERROR_MESSAGE_SIZE); } @@ -11785,7 +12174,7 @@ int x_catch_errors (dpy) Display *dpy; { - int count = specpdl_ptr - specpdl; + int count = SPECPDL_INDEX (); /* Make sure any errors from previous requests have been dealt with. */ XSync (dpy, False); @@ -11793,7 +12182,7 @@ x_catch_errors (dpy) record_unwind_protect (x_catch_errors_unwind, x_error_message_string); x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE); - XSTRING (x_error_message_string)->data[0] = 0; + SSET (x_error_message_string, 0, 0); return count; } @@ -11820,8 +12209,8 @@ x_check_errors (dpy, format) /* Make sure to catch any errors incurred so far. */ XSync (dpy, False); - if (XSTRING (x_error_message_string)->data[0]) - error (format, XSTRING (x_error_message_string)->data); + if (SREF (x_error_message_string, 0)) + error (format, SDATA (x_error_message_string)); } /* Nonzero if we had any X protocol errors @@ -11834,7 +12223,7 @@ x_had_errors_p (dpy) /* Make sure to catch any errors incurred so far. */ XSync (dpy, False); - return XSTRING (x_error_message_string)->data[0] != 0; + return SREF (x_error_message_string, 0) != 0; } /* Forget about any errors we have had, since we did x_catch_errors on DPY. */ @@ -11843,7 +12232,7 @@ void x_clear_errors (dpy) Display *dpy; { - XSTRING (x_error_message_string)->data[0] = 0; + SSET (x_error_message_string, 0, 0); } /* Stop catching X protocol errors and let them make Emacs die. @@ -11894,7 +12283,7 @@ x_connection_signal (signalnum) /* If we don't have an argument, */ static char *error_msg; -/* Function installed as fatal_error_signal_hook.in +/* Function installed as fatal_error_signal_hook in x_connection_closed. Print the X error message, and exit normally, instead of dumping core when XtCloseDisplay fails. */ @@ -12081,7 +12470,9 @@ x_new_font (f, fontname) f->output_data.x->font = (XFontStruct *) (fontp->font); f->output_data.x->baseline_offset = fontp->baseline_offset; f->output_data.x->fontset = -1; - + + x_compute_fringe_widths (f, 1); + /* Compute the scroll bar width in character columns. */ if (f->scroll_bar_pixel_width > 0) { @@ -12141,7 +12532,7 @@ x_new_fontset (f, fontsetname) to do. */ return fontset_name (fontset); - result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data)); + result = x_new_font (f, (SDATA (fontset_ascii (fontset)))); if (!STRINGP (result)) /* Can't load ASCII font. */ @@ -12153,12 +12544,96 @@ x_new_fontset (f, fontsetname) #ifdef HAVE_X_I18N if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea))) - xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data); + xic_set_xfontset (f, SDATA (fontset_ascii (fontset))); #endif return build_string (fontsetname); } +/* Compute actual fringe widths */ + +void +x_compute_fringe_widths (f, redraw) + struct frame *f; + int redraw; +{ + int o_left = f->output_data.x->left_fringe_width; + int o_right = f->output_data.x->right_fringe_width; + int o_cols = f->output_data.x->fringe_cols; + + Lisp_Object left_fringe = Fassq (Qleft_fringe, f->param_alist); + Lisp_Object right_fringe = Fassq (Qright_fringe, f->param_alist); + int left_fringe_width, right_fringe_width; + + if (!NILP (left_fringe)) + left_fringe = Fcdr (left_fringe); + if (!NILP (right_fringe)) + right_fringe = Fcdr (right_fringe); + + left_fringe_width = ((NILP (left_fringe) || !INTEGERP (left_fringe)) ? 8 : + XINT (left_fringe)); + right_fringe_width = ((NILP (right_fringe) || !INTEGERP (right_fringe)) ? 8 : + XINT (right_fringe)); + + if (left_fringe_width || right_fringe_width) + { + int left_wid = left_fringe_width >= 0 ? left_fringe_width : -left_fringe_width; + int right_wid = right_fringe_width >= 0 ? right_fringe_width : -right_fringe_width; + int conf_wid = left_wid + right_wid; + int font_wid = FONT_WIDTH (f->output_data.x->font); + int cols = (left_wid + right_wid + font_wid-1) / font_wid; + int real_wid = cols * font_wid; + if (left_wid && right_wid) + { + if (left_fringe_width < 0) + { + /* Left fringe width is fixed, adjust right fringe if necessary */ + f->output_data.x->left_fringe_width = left_wid; + f->output_data.x->right_fringe_width = real_wid - left_wid; + } + else if (right_fringe_width < 0) + { + /* Right fringe width is fixed, adjust left fringe if necessary */ + f->output_data.x->left_fringe_width = real_wid - right_wid; + f->output_data.x->right_fringe_width = right_wid; + } + else + { + /* Adjust both fringes with an equal amount. + Note that we are doing integer arithmetic here, so don't + lose a pixel if the total width is an odd number. */ + int fill = real_wid - conf_wid; + f->output_data.x->left_fringe_width = left_wid + fill/2; + f->output_data.x->right_fringe_width = right_wid + fill - fill/2; + } + } + else if (left_fringe_width) + { + f->output_data.x->left_fringe_width = real_wid; + f->output_data.x->right_fringe_width = 0; + } + else + { + f->output_data.x->left_fringe_width = 0; + f->output_data.x->right_fringe_width = real_wid; + } + f->output_data.x->fringe_cols = cols; + f->output_data.x->fringes_extra = real_wid; + } + else + { + f->output_data.x->left_fringe_width = 0; + f->output_data.x->right_fringe_width = 0; + f->output_data.x->fringe_cols = 0; + f->output_data.x->fringes_extra = 0; + } + + if (redraw && FRAME_VISIBLE_P (f)) + if (o_left != f->output_data.x->left_fringe_width || + o_right != f->output_data.x->right_fringe_width || + o_cols != f->output_data.x->fringe_cols) + redraw_frame (f); +} /*********************************************************************** X Input Methods @@ -12528,6 +13003,114 @@ x_set_offset (f, xoff, yoff, change_gravity) UNBLOCK_INPUT; } +/* Check if we need to resize the frame due to a fullscreen request. + If so needed, resize the frame. */ +static void +x_check_fullscreen (f) + struct frame *f; +{ + if (f->output_data.x->want_fullscreen & FULLSCREEN_BOTH) + { + int width, height, ign; + + x_real_positions (f, &f->output_data.x->left_pos, + &f->output_data.x->top_pos); + + x_fullscreen_adjust (f, &width, &height, &ign, &ign); + + /* We do not need to move the window, it shall be taken care of + when setting WM manager hints. + If the frame is visible already, the position is checked by + x_check_fullscreen_move. */ + if (f->width != width || f->height != height) + { + change_frame_size (f, height, width, 0, 1, 0); + SET_FRAME_GARBAGED (f); + cancel_mouse_face (f); + + /* Wait for the change of frame size to occur */ + f->output_data.x->want_fullscreen |= FULLSCREEN_WAIT; + + } + } +} + +/* If frame parameters are set after the frame is mapped, we need to move + the window. This is done in xfns.c. + Some window managers moves the window to the right position, some + moves the outer window manager window to the specified position. + Here we check that we are in the right spot. If not, make a second + move, assuming we are dealing with the second kind of window manager. */ +static void +x_check_fullscreen_move (f) + struct frame *f; +{ + if (f->output_data.x->want_fullscreen & FULLSCREEN_MOVE_WAIT) + { + int expect_top = f->output_data.x->top_pos; + int expect_left = f->output_data.x->left_pos; + + if (f->output_data.x->want_fullscreen & FULLSCREEN_HEIGHT) + expect_top = 0; + if (f->output_data.x->want_fullscreen & FULLSCREEN_WIDTH) + expect_left = 0; + + if (expect_top != f->output_data.x->top_pos + || expect_left != f->output_data.x->left_pos) + x_set_offset (f, expect_left, expect_top, 1); + + /* Just do this once */ + f->output_data.x->want_fullscreen &= ~FULLSCREEN_MOVE_WAIT; + } +} + + +/* Calculate fullscreen size. Return in *TOP_POS and *LEFT_POS the + wanted positions of the WM window (not emacs window). + Return in *WIDTH and *HEIGHT the wanted width and height of Emacs + window (FRAME_X_WINDOW). + */ +void +x_fullscreen_adjust (f, width, height, top_pos, left_pos) + struct frame *f; + int *width; + int *height; + int *top_pos; + int *left_pos; +{ + int newwidth = f->width, newheight = f->height; + + *top_pos = f->output_data.x->top_pos; + *left_pos = f->output_data.x->left_pos; + + if (f->output_data.x->want_fullscreen & FULLSCREEN_HEIGHT) + { + int ph; + + ph = FRAME_X_DISPLAY_INFO (f)->height; + newheight = PIXEL_TO_CHAR_HEIGHT (f, ph); + ph = CHAR_TO_PIXEL_HEIGHT (f, newheight) + - f->output_data.x->y_pixels_diff; + newheight = PIXEL_TO_CHAR_HEIGHT (f, ph); + *top_pos = 0; + } + + if (f->output_data.x->want_fullscreen & FULLSCREEN_WIDTH) + { + int pw; + + pw = FRAME_X_DISPLAY_INFO (f)->width; + newwidth = PIXEL_TO_CHAR_WIDTH (f, pw); + pw = CHAR_TO_PIXEL_WIDTH (f, newwidth) + - f->output_data.x->x_pixels_diff; + newwidth = PIXEL_TO_CHAR_WIDTH (f, pw); + *left_pos = 0; + } + + *width = newwidth; + *height = newheight; +} + /* Change the size of frame F's X window to COLS/ROWS in the case F doesn't have a widget. If CHANGE_GRAVITY is 1, we change to @@ -12549,8 +13132,9 @@ x_set_window_size_1 (f, change_gravity, cols, rows) : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f) : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font))); - f->output_data.x->flags_areas_extra - = FRAME_FLAGS_AREA_WIDTH (f); + + x_compute_fringe_widths (f, 0); + pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols); pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows); @@ -13113,6 +13697,8 @@ x_free_frame_resources (f) struct frame *f; { struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); + Lisp_Object bar; + struct scroll_bar *b; BLOCK_INPUT; @@ -13122,23 +13708,40 @@ x_free_frame_resources (f) { if (f->output_data.x->icon_desc) XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc); - + +#ifdef USE_X_TOOLKIT + /* Explicitly destroy the scroll bars of the frame. Without + this, we get "BadDrawable" errors from the toolkit later on, + presumably from expose events generated for the disappearing + toolkit scroll bars. */ + for (bar = FRAME_SCROLL_BARS (f); !NILP (bar); bar = b->next) + { + b = XSCROLL_BAR (bar); + x_scroll_bar_remove (b); + } +#endif + #ifdef HAVE_X_I18N if (FRAME_XIC (f)) free_frame_xic (f); #endif - - if (FRAME_X_WINDOW (f)) - XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); - + #ifdef USE_X_TOOLKIT if (f->output_data.x->widget) { XtDestroyWidget (f->output_data.x->widget); f->output_data.x->widget = NULL; } + /* Tooltips don't have widgets, only a simple X window, even if + we are using a toolkit. */ + else if (FRAME_X_WINDOW (f)) + XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); + free_frame_menubar (f); -#endif /* USE_X_TOOLKIT */ +#else /* !USE_X_TOOLKIT */ + if (FRAME_X_WINDOW (f)) + XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); +#endif /* !USE_X_TOOLKIT */ unload_color (f, f->output_data.x->foreground_pixel); unload_color (f, f->output_data.x->background_pixel); @@ -13146,7 +13749,7 @@ x_free_frame_resources (f) unload_color (f, f->output_data.x->cursor_foreground_pixel); unload_color (f, f->output_data.x->border_pixel); unload_color (f, f->output_data.x->mouse_pixel); - + if (f->output_data.x->scroll_bar_background_pixel != -1) unload_color (f, f->output_data.x->scroll_bar_background_pixel); if (f->output_data.x->scroll_bar_foreground_pixel != -1) @@ -13541,7 +14144,7 @@ x_list_fonts (f, pattern, size, maxnames) XFontStruct *font; unsigned long value; - font = XLoadQueryFont (dpy, XSTRING (pattern)->data); + font = XLoadQueryFont (dpy, SDATA (pattern)); if (x_had_errors_p (dpy)) { /* This error is perhaps due to insufficient memory on X @@ -13584,7 +14187,7 @@ x_list_fonts (f, pattern, size, maxnames) { /* We try at least 10 fonts because XListFonts will return auto-scaled fonts at the head. */ - names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10), + names = XListFonts (dpy, SDATA (pattern), max (maxnames, 10), &num_fonts); if (x_had_errors_p (dpy)) { @@ -13685,7 +14288,7 @@ x_list_fonts (f, pattern, size, maxnames) BLOCK_INPUT; count = x_catch_errors (dpy); thisinfo = XLoadQueryFont (dpy, - XSTRING (XCAR (tem))->data); + SDATA (XCAR (tem))); if (x_had_errors_p (dpy)) { /* This error is perhaps due to insufficient memory on X @@ -13865,9 +14468,9 @@ x_load_font (f, fontname, size) for (tail = font_names; CONSP (tail); tail = XCDR (tail)) if (dpyinfo->font_table[i].name && (!strcmp (dpyinfo->font_table[i].name, - XSTRING (XCAR (tail))->data) + SDATA (XCAR (tail))) || !strcmp (dpyinfo->font_table[i].full_name, - XSTRING (XCAR (tail))->data))) + SDATA (XCAR (tail))))) return (dpyinfo->font_table + i); } @@ -13885,7 +14488,7 @@ x_load_font (f, fontname, size) a bug of not finding a font even if the font surely exists and is loadable by XLoadQueryFont. */ if (size > 0 && !NILP (font_names)) - fontname = (char *) XSTRING (XCAR (font_names))->data; + fontname = (char *) SDATA (XCAR (font_names)); BLOCK_INPUT; count = x_catch_errors (FRAME_X_DISPLAY (f)); @@ -14038,10 +14641,10 @@ x_load_font (f, fontname, size) /* Set global flag fonts_changed_p to non-zero if the font loaded has a character with a smaller width than any other character - before, or if the font loaded has a smalle>r height than any + before, or if the font loaded has a smaller height than any other font loaded before. If this happens, it will make a glyph matrix reallocation necessary. */ - fonts_changed_p = x_compute_min_glyph_bounds (f); + fonts_changed_p |= x_compute_min_glyph_bounds (f); UNBLOCK_INPUT; return fontp; } @@ -14134,10 +14737,10 @@ static int x_initialized; the screen number from the server number. */ static int same_x_server (name1, name2) - char *name1, *name2; + const char *name1, *name2; { int seen_colon = 0; - unsigned char *system_name = XSTRING (Vsystem_name)->data; + const unsigned char *system_name = SDATA (Vsystem_name); int system_name_length = strlen (system_name); int length_until_period = 0; @@ -14218,10 +14821,12 @@ x_term_init (display_name, xrm_option, resource_name) argv[argc++] = "-xrm"; argv[argc++] = xrm_option; } - dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data, + stop_polling (); + dpy = XtOpenDisplay (Xt_app_con, SDATA (display_name), resource_name, EMACS_CLASS, emacs_options, XtNumber (emacs_options), &argc, argv); + start_polling (); #ifdef HAVE_X11XTR6 /* I think this is to compensate for XtSetLanguageProc. */ @@ -14233,7 +14838,7 @@ x_term_init (display_name, xrm_option, resource_name) #ifdef HAVE_X11R5 XSetLocaleModifiers (""); #endif - dpy = XOpenDisplay (XSTRING (display_name)->data); + dpy = XOpenDisplay (SDATA (display_name)); #endif /* not USE_X_TOOLKIT */ /* Detect failure. */ @@ -14255,8 +14860,8 @@ x_term_init (display_name, xrm_option, resource_name) for (share = x_display_list, tail = x_display_name_list; share; share = share->next, tail = XCDR (tail)) - if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data, - XSTRING (display_name)->data)) + if (same_x_server (SDATA (XCAR (XCAR (tail))), + SDATA (display_name))) break; if (share) dpyinfo->kboard = share->kboard; @@ -14302,11 +14907,11 @@ x_term_init (display_name, xrm_option, resource_name) #endif /* ! 0 */ dpyinfo->x_id_name - = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name)) - + STRING_BYTES (XSTRING (Vsystem_name)) + = (char *) xmalloc (SBYTES (Vinvocation_name) + + SBYTES (Vsystem_name) + 2); sprintf (dpyinfo->x_id_name, "%s@%s", - XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data); + SDATA (Vinvocation_name), SDATA (Vsystem_name)); /* Figure out which modifier bits mean what. */ x_find_modifier_meanings (dpyinfo); @@ -14352,6 +14957,7 @@ x_term_init (display_name, xrm_option, resource_name) dpyinfo->mouse_face_overlay = Qnil; dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0; dpyinfo->mouse_face_defer = 0; + dpyinfo->mouse_face_hidden = 0; dpyinfo->x_focus_frame = 0; dpyinfo->x_focus_event_frame = 0; dpyinfo->x_highlight_frame = 0; @@ -14368,8 +14974,8 @@ x_term_init (display_name, xrm_option, resource_name) build_string ("PrivateColormap"), Qnil, Qnil); if (STRINGP (value) - && (!strcmp (XSTRING (value)->data, "true") - || !strcmp (XSTRING (value)->data, "on"))) + && (!strcmp (SDATA (value), "true") + || !strcmp (SDATA (value), "on"))) dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap); } } @@ -14529,8 +15135,8 @@ x_term_init (display_name, xrm_option, resource_name) build_string ("Synchronous"), Qnil, Qnil); if (STRINGP (value) - && (!strcmp (XSTRING (value)->data, "true") - || !strcmp (XSTRING (value)->data, "on"))) + && (!strcmp (SDATA (value), "true") + || !strcmp (SDATA (value), "on"))) XSynchronize (dpyinfo->display, True); } @@ -14703,9 +15309,13 @@ x_initialize () /* Disable Window Change signals; they are handled by X events. */ #ifdef SIGWINCH signal (SIGWINCH, SIG_DFL); -#endif /* ! defined (SIGWINCH) */ +#endif /* SIGWINCH */ signal (SIGPIPE, x_connection_signal); + +#ifdef HAVE_X_SM + x_session_initialize (); +#endif } @@ -14724,6 +15334,11 @@ syms_of_xterm () staticpro (&Qvendor_specific_keysyms); Qvendor_specific_keysyms = intern ("vendor-specific-keysyms"); + staticpro (&Qutf_8); + Qutf_8 = intern ("utf-8"); + staticpro (&Qlatin_1); + Qlatin_1 = intern ("latin-1"); + staticpro (&last_mouse_press_frame); last_mouse_press_frame = Qnil; @@ -14737,6 +15352,10 @@ syms_of_xterm () staticpro (&previous_help_echo); help_echo_pos = -1; + DEFVAR_BOOL ("mouse-autoselect-window", &mouse_autoselect_window, + doc: /* *Non-nil means autoselect window with mouse pointer. */); + mouse_autoselect_window = 0; + DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p, doc: /* *Non-nil means draw block cursor as wide as the glyph under it. For example, if a block cursor is over a tab, it will be drawn as @@ -14746,7 +15365,7 @@ wide as that tab on the display. */); DEFVAR_BOOL ("x-use-underline-position-properties", &x_use_underline_position_properties, doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties. -Nil means ignore them. If you encounter fonts with bogus +nil means ignore them. If you encounter fonts with bogus UNDERLINE_POSITION font properties, for example 7x13 on XFree prior to 4.1, set this to nil. */); x_use_underline_position_properties = 1; @@ -14769,6 +15388,45 @@ Otherwise, value is a symbol describing the X toolkit. */); staticpro (&last_mouse_motion_frame); last_mouse_motion_frame = Qnil; + + Qmodifier_value = intern ("modifier-value"); + Qalt = intern ("alt"); + Fput (Qalt, Qmodifier_value, make_number (alt_modifier)); + Qhyper = intern ("hyper"); + Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier)); + Qmeta = intern ("meta"); + Fput (Qmeta, Qmodifier_value, make_number (meta_modifier)); + Qsuper = intern ("super"); + Fput (Qsuper, Qmodifier_value, make_number (super_modifier)); + + DEFVAR_LISP ("x-alt-keysym", &Vx_alt_keysym, + doc: /* Which keys Emacs uses for the alt modifier. +This should be one of the symbols `alt', `hyper', `meta', `super'. +For example, `alt' means use the Alt_L and Alt_R keysyms. The default +is nil, which is the same as `alt'. */); + Vx_alt_keysym = Qnil; + + DEFVAR_LISP ("x-hyper-keysym", &Vx_hyper_keysym, + doc: /* Which keys Emacs uses for the hyper modifier. +This should be one of the symbols `alt', `hyper', `meta', `super'. +For example, `hyper' means use the Hyper_L and Hyper_R keysyms. The +default is nil, which is the same as `hyper'. */); + Vx_hyper_keysym = Qnil; + + DEFVAR_LISP ("x-meta-keysym", &Vx_meta_keysym, + doc: /* Which keys Emacs uses for the meta modifier. +This should be one of the symbols `alt', `hyper', `meta', `super'. +For example, `meta' means use the Meta_L and Meta_R keysyms. The +default is nil, which is the same as `meta'. */); + Vx_meta_keysym = Qnil; + + DEFVAR_LISP ("x-super-keysym", &Vx_super_keysym, + doc: /* Which keys Emacs uses for the super modifier. +This should be one of the symbols `alt', `hyper', `meta', `super'. +For example, `super' means use the Super_L and Super_R keysyms. The +default is nil, which is the same as `super'. */); + Vx_super_keysym = Qnil; + } #endif /* HAVE_X_WINDOWS */