X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/812361a197fa4a2b3753845b26aa76ebd98ca1a9..dc05a16bad76f364242cbb4c3452d8d556a7288f:/src/xterm.c diff --git a/src/xterm.c b/src/xterm.c index 5580fbdda6..2f385266f4 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, 1993 Free Software Foundation, Inc. + Copyright (C) 1989, 1993, 1994 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -17,14 +17,6 @@ You should have received a copy of the GNU General Public License along with GNU Emacs; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* Serious problems: - - Kludge: dup2 is used to put the X-connection socket into desc # 0 - so that wait_reading_process_input will wait for it in place of - actual terminal input. - -*/ - /* Xt features made by Fred Pierresteguy. */ #define NEW_SELECTIONS @@ -71,7 +63,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "systty.h" #include "systime.h" +#ifndef INCLUDED_FCNTL #include +#endif #include #include #include @@ -98,6 +92,10 @@ extern Widget Xt_app_shell; extern void free_frame_menubar (); #endif /* USE_X_TOOLKIT */ +#ifndef USE_X_TOOLKIT +#define x_any_window_to_frame x_window_to_frame +#endif + #ifdef HAVE_X11 #define XMapWindow XMapRaised /* Raise them when mapping. */ #else /* ! defined (HAVE_X11) */ @@ -195,6 +193,9 @@ extern struct frame *updating_frame; x_focus_event_frame. */ struct frame *x_focus_frame; +/* This is a frame waiting to be autoraised, within XTread_socket. */ +struct frame *pending_autoraise_frame; + /* The last frame mentioned in a FocusIn or FocusOut event. This is separate from x_focus_frame, because whether or not LeaveNotify events cause us to lose focus depends on whether or not we have @@ -271,6 +272,25 @@ unsigned int x_mouse_grabbed; it's somewhat accurate. */ static Time last_mouse_movement_time; +/* These variables describe the range of text currently shown + in its mouse-face, together with the window they apply to. + As long as the mouse stays within this range, we need not + redraw anything on its account. */ +static int mouse_face_beg, mouse_face_end; +static Lisp_Object mouse_face_window; +static int mouse_face_face_id; + +/* 1 if a mouse motion event came and we didn't handle it right away because + gc was in progress. */ +static int mouse_face_deferred_gc; + +/* FRAME and X, Y position of mouse when last checked for highlighting. */ +static FRAME_PTR mouse_face_mouse_frame; +static int mouse_face_mouse_x, mouse_face_mouse_y; + +/* Nonzero means defer mouse-motion highlighting. */ +static int mouse_face_defer; + #ifdef HAVE_X11 /* `t' if a mouse button is depressed. */ @@ -289,6 +309,8 @@ extern Window requestor_window; /* Nonzero enables some debugging for the X interface code. */ extern int _Xdebug; +extern Qface, Qmouse_face; + #else /* ! defined (HAVE_X11) */ /* Bit patterns for the mouse cursor. */ @@ -328,8 +350,13 @@ extern FONT_TYPE *XOpenFont (); static void flashback (); static void redraw_previous_char (); +static void redraw_following_char (); static unsigned int x_x_to_emacs_modifiers (); +static void note_mouse_highlight (); +static void clear_mouse_face (); +static void show_mouse_face (); + #ifndef HAVE_X11 static void dumpqueue (); #endif /* HAVE_X11 */ @@ -363,6 +390,38 @@ XTupdate_begin (f) highlight = 0; BLOCK_INPUT; + + if (f == mouse_face_mouse_frame) + { + /* Don't do highlighting for mouse motion during the update. */ + mouse_face_defer = 1; + if (!NILP (mouse_face_window)) + { + int firstline, lastline, i; + struct window *w = XWINDOW (mouse_face_window); + + /* Find the first, and the last+1, lines affected by redisplay. */ + for (firstline = 0; firstline < f->height; firstline++) + if (FRAME_DESIRED_GLYPHS (f)->enable[firstline]) + break; + + lastline = f->height; + for (i = f->height - 1; i >= 0; i--) + { + if (FRAME_DESIRED_GLYPHS (f)->enable[i]) + break; + else + lastline = i; + } + + /* Can we tell that this update does not affect the window + where the mouse highlight is? If so, no need to turn off. */ + if (! (firstline > (XFASTINT (w->top) + window_internal_height (w)) + || lastline < XFASTINT (w->top))) + /* Otherwise turn off the mouse highlight now. */ + clear_mouse_face (); + } + } #ifndef HAVE_X11 dumpqueue (); #endif /* HAVE_X11 */ @@ -387,9 +446,36 @@ XTupdate_end (f) x_display_cursor (f, 1); + if (f == mouse_face_mouse_frame) + mouse_face_defer = 0; +#if 0 + /* This fails in the case of having updated only the echo area + if we have switched buffers. In that case, FRAME_CURRENT_GLYPHS + has no relation to the current contents, and its charstarts + have no relation to the contents of the window-buffer. + I don't know a clean way to check + for that case. window_end_valid isn't set up yet. */ + if (f == mouse_face_mouse_frame) + note_mouse_highlight (f, mouse_face_mouse_x, mouse_face_mouse_y); +#endif + XFlushQueue (); UNBLOCK_INPUT; } + +/* This is called after a redisplay on frame F. */ + +static +XTframe_up_to_date (f) + FRAME_PTR f; +{ + if (mouse_face_deferred_gc || f == mouse_face_mouse_frame) + { + note_mouse_highlight (mouse_face_mouse_frame, + mouse_face_mouse_x, mouse_face_mouse_y); + mouse_face_deferred_gc = 0; + } +} /* External interface to control of standout mode. Call this when about to modify line at position VPOS @@ -457,7 +543,10 @@ XTcursor_to (row, col) /* Display a sequence of N glyphs found at GP. WINDOW is the x-window to output to. LEFT and TOP are starting coords. - HL is 1 if this text is highlighted, 2 if the cursor is on it. + HL is 1 if this text is highlighted, 2 if the cursor is on it, + 3 if should appear in its mouse-face. + JUST_FOREGROUND if 1 means draw only the foreground; + don't alter the background. FONT is the default font to use (for glyphs whose font-code is 0). @@ -472,12 +561,13 @@ XTcursor_to (row, col) /* This is the multi-face code. */ static void -dumpglyphs (f, left, top, gp, n, hl) +dumpglyphs (f, left, top, gp, n, hl, just_foreground) struct frame *f; int left, top; register GLYPH *gp; /* Points to first GLYPH. */ register int n; /* Number of glyphs to display. */ int hl; + int just_foreground; { /* Holds characters to be displayed. */ char *buf = (char *) alloca (f->width * sizeof (*buf)); @@ -485,6 +575,7 @@ dumpglyphs (f, left, top, gp, n, hl) register int tlen = GLYPH_TABLE_LENGTH; register Lisp_Object *tbase = GLYPH_TABLE_BASE; Window window = FRAME_X_WINDOW (f); + int orig_left = left; while (n > 0) { @@ -493,7 +584,7 @@ dumpglyphs (f, left, top, gp, n, hl) int g = *gp; GLYPH_FOLLOW_ALIASES (tbase, tlen, g); - cf = GLYPH_FACE (g); + cf = FAST_GLYPH_FACE (g); /* Find the run of consecutive glyphs with the same face-code. Extract their character codes into BUF. */ @@ -502,10 +593,10 @@ dumpglyphs (f, left, top, gp, n, hl) { g = *gp; GLYPH_FOLLOW_ALIASES (tbase, tlen, g); - if (GLYPH_FACE (g) != cf) + if (FAST_GLYPH_FACE (g) != cf) break; - *cp++ = GLYPH_CHAR (g); + *cp++ = FAST_GLYPH_CHAR (g); --n; ++gp; } @@ -519,9 +610,12 @@ dumpglyphs (f, left, top, gp, n, hl) struct face *face = FRAME_DEFAULT_FACE (f); FONT_TYPE *font = FACE_FONT (face); GC gc = FACE_GC (face); - int defaulted = 1; int gc_temporary = 0; + /* HL = 3 means use a mouse face previously chosen. */ + if (hl == 3) + cf = mouse_face_face_id; + /* First look at the face of the text itself. */ if (cf != 0) { @@ -537,7 +631,6 @@ dumpglyphs (f, left, top, gp, n, hl) face = intern_face (f, FRAME_COMPUTED_FACES (f) [cf]); font = FACE_FONT (face); gc = FACE_GC (face); - defaulted = 0; } /* Then comes the distinction between modeline and normal text. */ @@ -548,7 +641,6 @@ dumpglyphs (f, left, top, gp, n, hl) face = FRAME_MODE_LINE_FACE (f); font = FACE_FONT (face); gc = FACE_GC (face); - defaulted = 0; } #define FACE_DEFAULT (~0) @@ -556,8 +648,7 @@ dumpglyphs (f, left, top, gp, n, hl) /* Now override that if the cursor's on this character. */ if (hl == 2) { - if (defaulted - || !face->font + if (!face->font || (int) face->font == FACE_DEFAULT) { gc = f->display.x->cursor_gc; @@ -569,7 +660,25 @@ dumpglyphs (f, left, top, gp, n, hl) unsigned long mask; xgcv.background = f->display.x->cursor_pixel; - xgcv.foreground = f->display.x->cursor_foreground_pixel; + if (face == FRAME_DEFAULT_FACE (f)) + xgcv.foreground = f->display.x->cursor_foreground_pixel; + else + xgcv.foreground = face->foreground; + /* If the glyph would be invisible, + try a different foreground. */ + if (xgcv.foreground == xgcv.background) + xgcv.foreground = face->background; + if (xgcv.foreground == xgcv.background) + xgcv.foreground = f->display.x->cursor_foreground_pixel; + if (xgcv.foreground == xgcv.background) + xgcv.foreground = face->foreground; + /* Make sure the cursor is distinct from text in this face. */ + if (xgcv.background == face->background + && xgcv.foreground == face->foreground) + { + xgcv.background = face->foreground; + xgcv.foreground = face->background; + } xgcv.font = face->font->fid; xgcv.graphics_exposures = 0; mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures; @@ -586,8 +695,36 @@ dumpglyphs (f, left, top, gp, n, hl) if ((int) font == FACE_DEFAULT) font = f->display.x->font; - XDrawImageString (x_current_display, window, gc, - left, top + FONT_BASE (font), buf, len); + if (just_foreground) + XDrawString (x_current_display, window, gc, + left, top + FONT_BASE (font), buf, len); + else + { + XDrawImageString (x_current_display, window, gc, + left, top + FONT_BASE (font), buf, len); + /* Clear the rest of the line's height. */ + if (f->display.x->line_height != FONT_HEIGHT (font)) + XClearArea (x_current_display, window, left, + top + FONT_HEIGHT (font), + FONT_WIDTH (font) * len, + /* This is how many pixels of height + we have to clear. */ + f->display.x->line_height - FONT_HEIGHT (font), + False); + } + +#if 0 /* Doesn't work, because it uses FRAME_CURRENT_GLYPHS, + which often is not up to date yet. */ + if (!just_foreground) + { + if (left == orig_left) + redraw_previous_char (f, PIXEL_TO_CHAR_COL (f, left), + PIXEL_TO_CHAR_ROW (f, top), hl == 1); + if (n == 0) + redraw_following_char (f, PIXEL_TO_CHAR_COL (f, left + len * FONT_WIDTH (font)), + PIXEL_TO_CHAR_ROW (f, top), hl == 1); + } +#endif if (gc_temporary) XFreeGC (x_current_display, gc); @@ -678,7 +815,7 @@ XTwrite_glyphs (start, len) dumpglyphs (f, CHAR_TO_PIXEL_COL (f, curs_x), CHAR_TO_PIXEL_ROW (f, curs_y), - start, len, highlight); + start, len, highlight, 0); /* If we drew on top of the cursor, note that it is turned off. */ if (curs_y == f->phys_cursor_y @@ -734,22 +871,60 @@ XTclear_end_of_line (first_unused) CHAR_TO_PIXEL_COL (f, curs_x), CHAR_TO_PIXEL_ROW (f, curs_y), FONT_WIDTH (f->display.x->font) * (first_unused - curs_x), - FONT_HEIGHT (f->display.x->font), False); + f->display.x->line_height, False); #if 0 - redraw_previous_char (f, curs_x, curs_y); + redraw_previous_char (f, curs_x, curs_y, highlight); #endif #else /* ! defined (HAVE_X11) */ XPixSet (FRAME_X_WINDOW (f), CHAR_TO_PIXEL_COL (f, curs_x), CHAR_TO_PIXEL_ROW (f, curs_y), FONT_WIDTH (f->display.x->font) * (first_unused - curs_x), - FONT_HEIGHT (f->display.x->font), + f->display.x->line_height, f->display.x->background_pixel); #endif /* ! defined (HAVE_X11) */ UNBLOCK_INPUT; } +static +XTclear_frame () +{ + int mask; + struct frame *f = updating_frame; + + if (f == 0) + f = selected_frame; + + f->phys_cursor_x = -1; /* Cursor not visible. */ + curs_x = 0; /* Nominal cursor position is top left. */ + curs_y = 0; + + BLOCK_INPUT; + + XClear (FRAME_X_WINDOW (f)); + + /* We have to clear the scroll bars, too. If we have changed + colors or something like that, then they should be notified. */ + x_scroll_bar_clear (f); + +#ifndef HAVE_X11 + dumpborder (f, 0); +#endif /* HAVE_X11 */ + + XFlushQueue (); + UNBLOCK_INPUT; +} + +#if 0 +/* This currently does not work because FRAME_CURRENT_GLYPHS doesn't + always contain the right glyphs to use. + + It also needs to be changed to look at the details of the font and + see whether there is really overlap, and do nothing when there is + not. This can use font_char_overlap_left and font_char_overlap_right, + but just how to use them is not clear. */ + /* Erase the character (if any) at the position just before X, Y in frame F, then redraw it and the character before it. This is necessary when we erase starting at X, @@ -757,9 +932,10 @@ XTclear_end_of_line (first_unused) Call this function with input blocked. */ static void -redraw_previous_char (f, x, y) +redraw_previous_char (f, x, y, highlight_flag) FRAME_PTR f; int x, y; + int highlight_flag; { /* Erase the character before the new ones, in case what was here before overlaps it. @@ -774,43 +950,144 @@ redraw_previous_char (f, x, y) CHAR_TO_PIXEL_COL (f, x - 1), CHAR_TO_PIXEL_ROW (f, y), FONT_WIDTH (f->display.x->font), - FONT_HEIGHT (f->display.x->font), False); + f->display.x->line_height, False); dumpglyphs (f, CHAR_TO_PIXEL_COL (f, start_x), CHAR_TO_PIXEL_ROW (f, y), &FRAME_CURRENT_GLYPHS (f)->glyphs[y][start_x], - x - start_x, highlight); + x - start_x, highlight_flag, 1); } } -static -XTclear_frame () +/* Erase the character (if any) at the position X, Y in frame F, + then redraw it and the character after it. + This is necessary when we erase endng at X, + in case the character after X overlaps into the one before X. + Call this function with input blocked. */ + +static void +redraw_following_char (f, x, y, highlight_flag) + FRAME_PTR f; + int x, y; + int highlight_flag; { - int mask; - struct frame *f = updating_frame; + int limit = FRAME_CURRENT_GLYPHS (f)->used[y]; + /* Erase the character after the new ones, in case + what was here before overlaps it. + Reoutput that character, and the following character + (in case the following character overlaps it). */ + if (x < limit + && FRAME_CURRENT_GLYPHS (f)->glyphs[y][x] != SPACEGLYPH) + { + int end_x = x + 2; + if (end_x > limit) + end_x = limit; + XClearArea (x_current_display, FRAME_X_WINDOW (f), + CHAR_TO_PIXEL_COL (f, x), + CHAR_TO_PIXEL_ROW (f, y), + FONT_WIDTH (f->display.x->font), + f->display.x->line_height, False); - if (f == 0) - f = selected_frame; + dumpglyphs (f, CHAR_TO_PIXEL_COL (f, x), + CHAR_TO_PIXEL_ROW (f, y), + &FRAME_CURRENT_GLYPHS (f)->glyphs[y][x], + end_x - x, highlight_flag, 1); + } +} +#endif /* 0 */ + +#if 0 /* Not in use yet */ - f->phys_cursor_x = -1; /* Cursor not visible. */ - curs_x = 0; /* Nominal cursor position is top left. */ - curs_y = 0; - - BLOCK_INPUT; +/* Return 1 if character C in font F extends past its left edge. */ - XClear (FRAME_X_WINDOW (f)); +static int +font_char_overlap_left (font, c) + XFontStruct *font; + int c; +{ + XCharStruct *s; - /* We have to clear the scroll bars, too. If we have changed - colors or something like that, then they should be notified. */ - x_scroll_bar_clear (f); + /* Find the bounding-box info for C. */ + if (font->per_char == 0) + s = &font->max_bounds; + else + { + int rowlen = font->max_char_or_byte2 - font->min_char_or_byte2 + 1; + int row, within; + + /* Decode char into row number (byte 1) and code within row (byte 2). */ + row = c >> 8; + within = c & 0177; + if (!(within >= font->min_char_or_byte2 + && within <= font->max_char_or_byte2 + && row >= font->min_byte1 + && row <= font->max_byte1)) + { + /* If char is out of range, try the font's default char instead. */ + c = font->default_char; + row = c >> (INTBITS - 8); + within = c & 0177; + } + if (!(within >= font->min_char_or_byte2 + && within <= font->max_char_or_byte2 + && row >= font->min_byte1 + && row <= font->max_byte1)) + /* Still out of range means this char does not overlap. */ + return 0; + else + /* We found the info for this char. */ + s = (font->per_char + (within - font->min_char_or_byte2) + + row * rowlen); + } -#ifndef HAVE_X11 - dumpborder (f, 0); -#endif /* HAVE_X11 */ + return (s && s->lbearing < 0); +} - XFlushQueue (); - UNBLOCK_INPUT; +/* Return 1 if character C in font F extends past its right edge. */ + +static int +font_char_overlap_right (font, c) + XFontStruct *font; + int c; +{ + XCharStruct *s; + + /* Find the bounding-box info for C. */ + if (font->per_char == 0) + s = &font->max_bounds; + else + { + int rowlen = font->max_char_or_byte2 - font->min_char_or_byte2 + 1; + int row, within; + + /* Decode char into row number (byte 1) and code within row (byte 2). */ + row = c >> 8; + within = c & 0177; + if (!(within >= font->min_char_or_byte2 + && within <= font->max_char_or_byte2 + && row >= font->min_byte1 + && row <= font->max_byte1)) + { + /* If char is out of range, try the font's default char instead. */ + c = font->default_char; + row = c >> (INTBITS - 8); + within = c & 0177; + } + if (!(within >= font->min_char_or_byte2 + && within <= font->max_char_or_byte2 + && row >= font->min_byte1 + && row <= font->max_byte1)) + /* Still out of range means this char does not overlap. */ + return 0; + else + /* We found the info for this char. */ + s = (font->per_char + (within - font->min_char_or_byte2) + + row * rowlen); + } + + return (s && s->rbearing >= s->width); } +#endif /* 0 */ /* Invert the middle quarter of the frame for .15 sec. */ @@ -1013,14 +1290,14 @@ stufflines (n) FRAME_X_WINDOW (f), f->display.x->normal_gc, intborder, CHAR_TO_PIXEL_ROW (f, topregion), f->width * FONT_WIDTH (f->display.x->font), - length * FONT_HEIGHT (f->display.x->font), intborder, + length * f->display.x->line_height, intborder, CHAR_TO_PIXEL_ROW (f, newtop)); #else /* ! defined (HAVE_X11) */ XMoveArea (FRAME_X_WINDOW (f), intborder, CHAR_TO_PIXEL_ROW (f, topregion), intborder, CHAR_TO_PIXEL_ROW (f, newtop), f->width * FONT_WIDTH (f->display.x->font), - length * FONT_HEIGHT (f->display.x->font)); + length * f->display.x->line_height); /* Now we must process any ExposeRegion events that occur if the area being copied from is obscured. We can't let it wait because further i/d operations @@ -1037,13 +1314,13 @@ stufflines (n) XClearArea (x_current_display, FRAME_X_WINDOW (f), intborder, CHAR_TO_PIXEL_ROW (f, topregion), f->width * FONT_WIDTH (f->display.x->font), - n * FONT_HEIGHT (f->display.x->font), False); + n * f->display.x->line_height, False); #else /* ! defined (HAVE_X11) */ XPixSet (FRAME_X_WINDOW (f), intborder, CHAR_TO_PIXEL_ROW (f, topregion), f->width * FONT_WIDTH (f->display.x->font), - n * FONT_HEIGHT (f->display.x->font), + n * f->display.x->line_height, f->display.x->background_pixel); #endif /* ! defined (HAVE_X11) */ } @@ -1075,12 +1352,12 @@ scraplines (n) XClearArea (x_current_display, FRAME_X_WINDOW (f), intborder, CHAR_TO_PIXEL_ROW (f, curs_y), f->width * FONT_WIDTH (f->display.x->font), - (flexlines - curs_y) * FONT_HEIGHT (f->display.x->font), False); + (flexlines - curs_y) * f->display.x->line_height, False); #else /* ! defined (HAVE_X11) */ XPixSet (FRAME_X_WINDOW (f), intborder, CHAR_TO_PIXEL_ROW (f, curs_y), f->width * FONT_WIDTH (f->display.x->font), - (flexlines - curs_y) * FONT_HEIGHT (f->display.x->font), + (flexlines - curs_y) * f->display.x->line_height, f->display.x->background_pixel); #endif /* ! defined (HAVE_X11) */ } @@ -1093,20 +1370,20 @@ scraplines (n) intborder, CHAR_TO_PIXEL_ROW (f, curs_y + n), f->width * FONT_WIDTH (f->display.x->font), - (flexlines - (curs_y + n)) * FONT_HEIGHT (f->display.x->font), + (flexlines - (curs_y + n)) * f->display.x->line_height, intborder, CHAR_TO_PIXEL_ROW (f, curs_y)); XClearArea (x_current_display, FRAME_X_WINDOW (f), intborder, CHAR_TO_PIXEL_ROW (f, flexlines - n), f->width * FONT_WIDTH (f->display.x->font), - n * FONT_HEIGHT (f->display.x->font), False); + n * f->display.x->line_height, False); #else /* ! defined (HAVE_X11) */ XMoveArea (FRAME_X_WINDOW (f), intborder, CHAR_TO_PIXEL_ROW (f, curs_y + n), intborder, CHAR_TO_PIXEL_ROW (f, curs_y), f->width * FONT_WIDTH (f->display.x->font), - (flexlines - (curs_y + n)) * FONT_HEIGHT (f->display.x->font)); + (flexlines - (curs_y + n)) * f->display.x->line_height); /* Now we must process any ExposeRegion events that occur if the area being copied from is obscured. We can't let it wait because further i/d operations @@ -1115,7 +1392,7 @@ scraplines (n) XPixSet (FRAME_X_WINDOW (f), intborder, CHAR_TO_PIXEL_ROW (f, flexlines - n), f->width * FONT_WIDTH (f->display.x->font), - n * FONT_HEIGHT (f->display.x->font), f->display.x->background_pixel); + n * f->display.x->line_height, f->display.x->background_pixel); #endif /* ! defined (HAVE_X11) */ } } @@ -1176,17 +1453,17 @@ dumprectangle (f, left, top, cols, rows) /* If the rectangle includes any of the internal border area, redisplay the border emphasis. */ if (top < intborder || left < intborder - || bottom > intborder + f->height * FONT_HEIGHT (f->display.x->font) - || right > intborder + f->width * FONT_WIDTH (f->display.x->font)) + || bottom > intborder + f->height * f->display.x->line_height + || right > intborder + f->width * f->display.x->line_height) dumpborder (f, 0); } -#endif /* HAVE_X11 Window manger does this for X11. */ +#endif /* not HAVE_X11 Window manger does this for X11. */ /* Convert rectangle edges in pixels to edges in chars. Round down for left and top, up for right and bottom. */ top = PIXEL_TO_CHAR_ROW (f, top); left = PIXEL_TO_CHAR_COL (f, left); - bottom += (FONT_HEIGHT (f->display.x->font) - 1); + bottom += (f->display.x->line_height - 1); right += (FONT_WIDTH (f->display.x->font) - 1); bottom = PIXEL_TO_CHAR_ROW (f, bottom); right = PIXEL_TO_CHAR_COL (f, right); @@ -1231,7 +1508,7 @@ dumprectangle (f, left, top, cols, rows) CHAR_TO_PIXEL_COL (f, left), CHAR_TO_PIXEL_ROW (f, y), line, min (cols, active_frame->used[y] - left), - active_frame->highlight[y]); + active_frame->highlight[y], 0); } /* Turn the cursor on if we turned it off. */ @@ -1301,7 +1578,7 @@ x_do_pending_expose () / FONT_WIDTH (f->display.x->font)); temp_height = ((windowinfo.height- 2 * intborder - f->display.x->h_scroll_bar_height) - / FONT_HEIGHT (f->display.x->font)); + / f->display.x->line_height); if (temp_width != f->width || temp_height != f->height) { change_frame_size (f, max (1, temp_height), @@ -1439,7 +1716,9 @@ x_new_focus_frame (frame) #endif /* ! 0 */ if (x_focus_frame && x_focus_frame->auto_raise) - x_raise_frame (x_focus_frame); + pending_autoraise_frame = x_focus_frame; + else + pending_autoraise_frame = 0; } XTframe_rehighlight (); @@ -1542,6 +1821,10 @@ x_find_modifier_meanings () KeyCode code = mods->modifiermap[(row * mods->max_keypermod) + col]; + /* Zeroes are used for filler. Skip them. */ + if (code == 0) + continue; + /* Are any of this keycode's keysyms a meta key? */ { int code_col; @@ -1601,31 +1884,6 @@ x_find_modifier_meanings () XFreeModifiermap (mods); } -/* Prepare a menu-event in *RESULT for placement in the input queue. */ - -static Lisp_Object -construct_menu_click (result, event, f) - struct input_event *result; - XButtonEvent *event; - struct frame *f; -{ - /* Make the event type no_event; we'll change that when we decide - otherwise. */ - result->kind = mouse_click; - XSET (result->code, Lisp_Int, event->button - Button1); - result->timestamp = event->time; - result->modifiers = (x_x_to_emacs_modifiers (event->state) - | (event->type == ButtonRelease - ? up_modifier - : down_modifier)); - - { - XFASTINT (result->x) = event->x; - XFASTINT (result->y) = -1; /* special meaning for menubar */ - XSET (result->frame_or_window, Lisp_Frame, f); - } -} - /* Convert between the modifier bits X uses and the modifier bits Emacs uses. */ static unsigned int @@ -1676,7 +1934,7 @@ x_is_vendor_fkey (sym) that the glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is nonzero, do not force the value into range. */ -static void +void pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip) FRAME_PTR f; register int pix_x, pix_y; @@ -1689,7 +1947,7 @@ pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip) if (pix_x < 0) pix_x -= FONT_WIDTH ((f)->display.x->font) - 1; if (pix_y < 0) - pix_y -= FONT_HEIGHT ((f)->display.x->font) - 1; + pix_y -= (f)->display.x->line_height - 1; pix_x = PIXEL_TO_CHAR_COL (f, pix_x); pix_y = PIXEL_TO_CHAR_ROW (f, pix_y); @@ -1697,7 +1955,7 @@ pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip) if (bounds) { bounds->width = FONT_WIDTH (f->display.x->font); - bounds->height = FONT_HEIGHT (f->display.x->font); + bounds->height = f->display.x->line_height; bounds->x = CHAR_TO_PIXEL_COL (f, pix_x); bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y); } @@ -1719,6 +1977,16 @@ pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip) *y = pix_y; } +void +glyph_to_pixel_coords (f, x, y, pix_x, pix_y) + FRAME_PTR f; + register int x, y; + register int *pix_x, *pix_y; +{ + *pix_x = CHAR_TO_PIXEL_COL (f, x); + *pix_y = CHAR_TO_PIXEL_ROW (f, y); +} + /* Prepare a mouse-event in *RESULT for placement in the input queue. If the event is a button press, then note that we have grabbed @@ -1758,12 +2026,39 @@ construct_mouse_click (result, event, f) { int row, column; +#if 0 pixel_to_glyph_coords (f, event->x, event->y, &column, &row, NULL, 0); XFASTINT (result->x) = column; XFASTINT (result->y) = row; +#endif + XSET (result->x, Lisp_Int, event->x); + XSET (result->y, Lisp_Int, event->y); XSET (result->frame_or_window, Lisp_Frame, f); } } + +/* Prepare a menu-event in *RESULT for placement in the input queue. */ + +static Lisp_Object +construct_menu_click (result, event, f) + struct input_event *result; + XButtonEvent *event; + struct frame *f; +{ + /* Make the event type no_event; we'll change that when we decide + otherwise. */ + result->kind = mouse_click; + XSET (result->code, Lisp_Int, event->button - Button1); + result->timestamp = event->time; + result->modifiers = (x_x_to_emacs_modifiers (event->state) + | (event->type == ButtonRelease + ? up_modifier + : down_modifier)); + + XSET (result->x, Lisp_Int, event->x); + XSET (result->y, Lisp_Int, -1); + XSET (result->frame_or_window, Lisp_Frame, f); +} /* Function to report a mouse movement to the mainstream Emacs code. The input handler calls this. @@ -1772,6 +2067,7 @@ construct_mouse_click (result, event, f) If the mouse is over a different glyph than it was last time, tell the mainstream emacs code by setting mouse_moved. If not, ask for another motion event, so we can check again the next time it moves. */ + static void note_mouse_movement (frame, event) FRAME_PTR frame; @@ -1788,6 +2084,18 @@ note_mouse_movement (frame, event) { mouse_moved = 1; last_mouse_scroll_bar = Qnil; + + note_mouse_highlight (frame, event->x, event->y); + + /* Ask for another mouse motion event. */ + { + int dummy; + + XQueryPointer (event->display, event->window, + (Window *) &dummy, (Window *) &dummy, + &dummy, &dummy, &dummy, &dummy, + (unsigned int *) &dummy); + } } else { @@ -1803,6 +2111,301 @@ note_mouse_movement (frame, event) } } +/* This is used for debugging, to turn off note_mouse_highlight. */ +static int disable_mouse_highlight; + +/* Take proper action when the mouse has moved to position X, Y on frame F + as regards highlighting characters that have mouse-face properties. + Also dehighlighting chars where the mouse was before. */ + +static void +note_mouse_highlight (f, x, y) + FRAME_PTR f; +{ + int row, column, portion; + XRectangle new_glyph; + Lisp_Object window; + struct window *w; + + if (disable_mouse_highlight) + return; + + mouse_face_mouse_x = x; + mouse_face_mouse_y = y; + mouse_face_mouse_frame = f; + + if (mouse_face_defer) + return; + + if (gc_in_progress) + { + mouse_face_deferred_gc = 1; + return; + } + + /* Find out which glyph the mouse is on. */ + pixel_to_glyph_coords (f, x, y, &column, &row, + &new_glyph, x_mouse_grabbed); + + /* Which window is that in? */ + window = window_from_coordinates (f, column, row, &portion); + w = XWINDOW (window); + + /* If we were displaying active text in another window, clear that. */ + if (! EQ (window, mouse_face_window)) + clear_mouse_face (); + + /* Are we in a window whose display is up to date? + And verify the buffer's text has not changed. */ + if (WINDOWP (window) && portion == 0 + && EQ (w->window_end_valid, w->buffer) + && w->last_modified == BUF_MODIFF (XBUFFER (w->buffer))) + { + int *ptr = FRAME_CURRENT_GLYPHS (f)->charstarts[row]; + int i, pos; + + /* Find which buffer position the mouse corresponds to. */ + for (i = column; i >= 0; i--) + if (ptr[i] > 0) + break; + pos = ptr[i]; + /* Is it outside the displayed active region (if any)? */ + if (pos > 0 + && ! (EQ (window, mouse_face_window) + && pos >= mouse_face_beg && pos < mouse_face_end)) + { + Lisp_Object mouse_face, overlay, position; + Lisp_Object *overlay_vec; + int len, noverlays, ignor1; + struct buffer *obuf; + int obegv, ozv; + + /* If we get an out-of-range value, return now; avoid an error. */ + if (pos > BUF_Z (XBUFFER (w->buffer))) + return; + + /* Make the window's buffer temporarily current for + overlays_at and compute_char_face. */ + obuf = current_buffer; + current_buffer = XBUFFER (w->buffer); + obegv = BEGV; + ozv = ZV; + BEGV = BEG; + ZV = Z; + + /* Yes. Clear the display of the old active region, if any. */ + clear_mouse_face (); + + /* Is this char mouse-active? */ + XSET (position, Lisp_Int, pos); + + len = 10; + overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object)); + + /* Put all the overlays we want in a vector in overlay_vec. + Store the length in len. */ + noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len, &ignor1); + noverlays = sort_overlays (overlay_vec, noverlays, w); + + /* Find the highest priority overlay that has a mouse-face prop. */ + overlay = Qnil; + for (i = 0; i < noverlays; i++) + { + mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face); + if (!NILP (mouse_face)) + { + overlay = overlay_vec[i]; + break; + } + } + free (overlay_vec); + /* If no overlay applies, get a text property. */ + if (NILP (overlay)) + mouse_face = Fget_text_property (position, Qmouse_face, w->buffer); + + /* Handle the overlay case. */ + if (! NILP (overlay)) + { + /* Find the range of text around this char that + should be active. */ + Lisp_Object before, after; + int ignore; + + before = Foverlay_start (overlay); + after = Foverlay_end (overlay); + /* Record this as the current active region. */ + mouse_face_beg = XFASTINT (before); + mouse_face_end = XFASTINT (after); + mouse_face_window = window; + mouse_face_face_id = compute_char_face (f, w, pos, 0, 0, + &ignore, pos + 1, 1); + + /* Display it as active. */ + show_mouse_face (1); + } + /* Handle the text property case. */ + else if (! NILP (mouse_face)) + { + /* Find the range of text around this char that + should be active. */ + Lisp_Object before, after, beginning, end; + int ignore; + + beginning = Fmarker_position (w->start); + XSET (end, Lisp_Int, + (BUF_Z (XBUFFER (w->buffer)) + - XFASTINT (w->window_end_pos))); + before + = Fprevious_single_property_change (make_number (pos + 1), + Qmouse_face, + w->buffer, beginning); + after + = Fnext_single_property_change (position, Qmouse_face, + w->buffer, end); + /* Record this as the current active region. */ + mouse_face_beg = XFASTINT (before); + mouse_face_end = XFASTINT (after); + mouse_face_window = window; + mouse_face_face_id + = compute_char_face (f, w, pos, 0, 0, + &ignore, pos + 1, 1); + + /* Display it as active. */ + show_mouse_face (1); + } + BEGV = obegv; + ZV = ozv; + current_buffer = obuf; + } + else if (pos <= 0) + clear_mouse_face (); + } +} + +/* Find the row and column of position POS in window WINDOW. + Store them in *COLUMNP and *ROWP. + This assumes display in WINDOW is up to date. + If POS is above start of WINDOW, return coords + of start of first screen line. + If POS is after end of WINDOW, return coords of end of last screen line. */ + +static int +fast_find_position (window, pos, columnp, rowp) + Lisp_Object window; + int pos; + int *columnp, *rowp; +{ + struct window *w = XWINDOW (window); + FRAME_PTR f = XFRAME (WINDOW_FRAME (w)); + int i; + int row; + int left = w->left; + int top = w->top; + int height = XFASTINT (w->height) - ! MINI_WINDOW_P (w); + int width = window_internal_width (w); + int *charstarts; + int lastcol; + + for (i = 0; + i < height; + i++) + { + int linestart = FRAME_CURRENT_GLYPHS (f)->charstarts[top + i][left]; + if (linestart > pos) + break; + if (linestart > 0) + row = i; + } + + charstarts = FRAME_CURRENT_GLYPHS (f)->charstarts[top + row]; + lastcol = left; + for (i = 0; i < width; i++) + { + if (charstarts[left + i] == pos) + { + *rowp = row + top; + *columnp = i + left; + return 1; + } + else if (charstarts[left + i] > pos) + lastcol = left + i; + } + + *rowp = row + top; + *columnp = lastcol; + return 0; +} + +/* Display the active region described by mouse_face_* + in its mouse-face if HL > 0, in its normal face if HL = 0. */ + +static void +show_mouse_face (hl) + int hl; +{ + int begcol, begrow, endcol, endrow; + struct window *w = XWINDOW (mouse_face_window); + int width = window_internal_width (w); + FRAME_PTR f = XFRAME (WINDOW_FRAME (w)); + int i; + int curs_x = f->phys_cursor_x; + int curs_y = f->phys_cursor_y; + int cursor_off = 0; + + fast_find_position (mouse_face_window, mouse_face_beg, + &begcol, &begrow); + fast_find_position (mouse_face_window, mouse_face_end, + &endcol, &endrow); + + for (i = begrow; i <= endrow; i++) + { + int column = (i == begrow ? begcol : w->left); + int endcolumn = (i == endrow ? endcol : w->left + width); + endcolumn = min (endcolumn, FRAME_CURRENT_GLYPHS (f)->used[i] - w->left); + + /* If the cursor's in the text we are about to rewrite, + turn the cursor off. */ + if (i == curs_y + && (curs_x >= begrow - 1 || curs_x <= endrow)) + { + x_display_cursor (f, 0); + cursor_off = 1; + } + + dumpglyphs (f, + CHAR_TO_PIXEL_COL (f, column), + CHAR_TO_PIXEL_ROW (f, i), + FRAME_CURRENT_GLYPHS (f)->glyphs[i] + column, + endcolumn - column, + /* Highlight with mouse face if hl > 0. */ + hl > 0 ? 3 : 0, 0); + } + + /* If we turned the cursor off, turn it back on. */ + if (cursor_off) + x_display_cursor (f, 1); + + /* Change the mouse cursor according to the value of HL. */ + if (hl > 0) + XDefineCursor (XDISPLAY FRAME_X_WINDOW (f), f->display.x->cross_cursor); + else + XDefineCursor (XDISPLAY FRAME_X_WINDOW (f), f->display.x->text_cursor); +} + +/* Clear out the mouse-highlighted active region. + Redraw it unhighlighted first. */ + +static void +clear_mouse_face () +{ + if (! NILP (mouse_face_window)) + show_mouse_face (0); + + mouse_face_beg = -1; + mouse_face_end = -1; + mouse_face_window = Qnil; +} + static struct scroll_bar *x_window_to_scroll_bar (); static void x_scroll_bar_report_motion (); @@ -1933,7 +2536,7 @@ XTmouse_position (f, bar_window, part, x, y, time) never use them in that case.) */ /* Is win one of our frames? */ - f1 = x_window_to_frame (win); + f1 = x_any_window_to_frame (win); } /* If not, is it one of our scroll bars? */ @@ -1951,10 +2554,11 @@ XTmouse_position (f, bar_window, part, x, y, time) if (f1) { - /* Ok, we found a frame. Convert from pixels to characters - and store all the values. */ + int ignore1, ignore2; - pixel_to_glyph_coords (f1, win_x, win_y, &win_x, &win_y, + /* Ok, we found a frame. Store all the values. */ + + pixel_to_glyph_coords (f1, win_x, win_y, &ignore1, &ignore2, &last_mouse_glyph, x_mouse_grabbed); *bar_window = Qnil; @@ -1989,9 +2593,9 @@ x_window_to_scroll_bar (window_id) XGCTYPE (tail) == Lisp_Cons; tail = XCONS (tail)->cdr) { - Lisp_Object frame = XCONS (tail)->car; - Lisp_Object bar, condemned; + Lisp_Object frame, bar, condemned; + frame = XCONS (tail)->car; /* All elements of Vframe_list should be frames. */ if (XGCTYPE (frame) != Lisp_Frame) abort (); @@ -2423,12 +3027,6 @@ x_scroll_bar_expose (bar, event) /* x, y, width, height */ 0, 0, XINT (bar->width) - 1, XINT (bar->height) - 1); - /* Draw another line to make the extra-thick border on the right. */ - XFillRectangle (x_current_display, w, gc, - - /* x, y, width, height */ - XINT (bar->width) - 2, 1, 1, XINT (bar->height) - 2); - UNBLOCK_INPUT; } @@ -2819,7 +3417,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected) } else if (event.xclient.data.l[0] == Xatom_wm_delete_window) { - struct frame *f = x_window_to_frame (event.xclient.window); + struct frame *f = x_any_window_to_frame (event.xclient.window); if (f) { @@ -3070,7 +3668,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected) #ifdef HAVE_X11 case UnmapNotify: - f = x_window_to_frame (event.xunmap.window); + f = x_any_window_to_frame (event.xunmap.window); if (f) /* F may no longer exist if the frame was deleted. */ { @@ -3126,7 +3724,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected) #ifdef HAVE_X11 case KeyPress: - f = x_window_to_frame (event.xkey.window); + f = x_any_window_to_frame (event.xkey.window); if (f != 0) { @@ -3319,7 +3917,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected) then a mere LeaveNotify is enough to free you. */ case EnterNotify: - f = x_window_to_frame (event.xcrossing.window); + f = x_any_window_to_frame (event.xcrossing.window); if (event.xcrossing.focus) /* Entered Window */ { @@ -3340,7 +3938,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected) break; case FocusIn: - f = x_window_to_frame (event.xfocus.window); + f = x_any_window_to_frame (event.xfocus.window); if (event.xfocus.detail != NotifyPointer) x_focus_event_frame = f; if (f) @@ -3352,7 +3950,12 @@ XTread_socket (sd, bufp, numchars, waitp, expected) case LeaveNotify: - f = x_window_to_frame (event.xcrossing.window); + f = x_any_window_to_frame (event.xcrossing.window); + + if (f == mouse_face_mouse_frame) + /* If we move outside the frame, + then we're certainly no longer on any text in the frame. */ + clear_mouse_face (); if (event.xcrossing.focus) { @@ -3374,7 +3977,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected) break; case FocusOut: - f = x_window_to_frame (event.xfocus.window); + f = x_any_window_to_frame (event.xfocus.window); if (event.xfocus.detail != NotifyPointer && f == x_focus_event_frame) x_focus_event_frame = 0; @@ -3437,6 +4040,10 @@ XTread_socket (sd, bufp, numchars, waitp, expected) if (bar) x_scroll_bar_note_movement (bar, &event); + + /* If we move outside the frame, + then we're certainly no longer on any text in the frame. */ + clear_mouse_face (); } } #ifdef USE_X_TOOLKIT @@ -3445,11 +4052,43 @@ XTread_socket (sd, bufp, numchars, waitp, expected) break; case ConfigureNotify: + f = x_any_window_to_frame (event.xconfigure.window); #ifdef USE_X_TOOLKIT - /* process done in widget.c */ - goto OTHER; + if (f + && ! event.xconfigure.send_event + && (event.xconfigure.window == XtWindow (f->display.x->widget))) + { + Window win, child; + int win_x, win_y; + + /* Find the position of the outside upper-left corner of + the window, in the root coordinate system. Don't + refer to the parent window here; we may be processing + this event after the window manager has changed our + parent, but before we have reached the ReparentNotify. */ + XTranslateCoordinates (x_current_display, + + /* From-window, to-window. */ + XtWindow (f->display.x->widget), + ROOT_WINDOW, + + /* From-position, to-position. */ + -event.xconfigure.border_width, + -event.xconfigure.border_width, + &win_x, &win_y, + + /* Child of win. */ + &child); + event.xconfigure.x = win_x; + event.xconfigure.y = win_y; + + f->display.x->pixel_width = event.xconfigure.width; + f->display.x->pixel_height = event.xconfigure.height; + f->display.x->left_pos = event.xconfigure.x; + f->display.x->top_pos = event.xconfigure.y; + } + goto OTHER; #else /* not USE_X_TOOLKIT */ - f = x_window_to_frame (event.xconfigure.window); if (f) { int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height); @@ -3664,6 +4303,16 @@ XTread_socket (sd, bufp, numchars, waitp, expected) x_do_pending_expose (); #endif + /* If the focus was just given to an autoraising frame, + raise it now. */ +#ifdef HAVE_X11 + if (pending_autoraise_frame) + { + x_raise_frame (pending_autoraise_frame); + pending_autoraise_frame = 0; + } +#endif + UNBLOCK_INPUT; return count; } @@ -3746,7 +4395,7 @@ x_draw_box (f) int left = CHAR_TO_PIXEL_COL (f, f->cursor_x); int top = CHAR_TO_PIXEL_ROW (f, f->cursor_y); int width = FONT_WIDTH (f->display.x->font); - int height = FONT_HEIGHT (f->display.x->font); + int height = f->display.x->line_height; #ifdef HAVE_X11 XDrawRectangle (x_current_display, FRAME_X_WINDOW (f), @@ -3792,7 +4441,7 @@ clear_cursor (f) XPixSet (FRAME_X_WINDOW (f), CHAR_TO_PIXEL_COL (f, f->phys_cursor_x), CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y), - FONT_WIDTH (f->display.x->font), FONT_HEIGHT (f->display.x->font), + FONT_WIDTH (f->display.x->font), f->display.x->line_height, f->display.x->background_pixel); #endif /* ! defined (HAVE_X11) */ f->phys_cursor_x = -1; @@ -3812,7 +4461,7 @@ x_draw_single_glyph (f, row, column, glyph, highlight) dumpglyphs (f, CHAR_TO_PIXEL_COL (f, column), CHAR_TO_PIXEL_ROW (f, row), - &glyph, 1, highlight); + &glyph, 1, highlight, 0); } static void @@ -3867,7 +4516,7 @@ x_display_bar_cursor (f, on) f->display.x->cursor_gc, CHAR_TO_PIXEL_COL (f, curs_x), CHAR_TO_PIXEL_ROW (f, curs_y), - 1, FONT_HEIGHT (f->display.x->font)); + 1, f->display.x->line_height); f->phys_cursor_x = curs_x; f->phys_cursor_y = curs_y; @@ -3920,6 +4569,14 @@ x_display_box_cursor (f, on) || (f->display.x->current_cursor != hollow_box_cursor && (f != x_highlight_frame)))) { + /* If the font is not as tall as a whole line, + we must explicitly clear the line's whole height. */ + if (FONT_HEIGHT (f->display.x->font) != f->display.x->line_height) + XClearArea (x_current_display, FRAME_X_WINDOW (f), + CHAR_TO_PIXEL_COL (f, f->phys_cursor_x), + CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y), + FONT_WIDTH (f->display.x->font), + f->display.x->line_height, False); /* Erase the cursor by redrawing the character underneath it. */ x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x, f->phys_cursor_glyph, @@ -4273,6 +4930,17 @@ x_check_errors (format) } } +/* Nonzero if we had any X protocol errors since we did x_catch_errors. */ + +int +x_had_errors_p () +{ + /* Make sure to catch any errors incurred so far. */ + XSync (x_current_display, False); + + return x_caught_error_message[0] != 0; +} + /* Stop catching X protocol errors and let them make Emacs die. */ void @@ -4424,12 +5092,18 @@ x_new_font (f, fontname) XSetFont (x_current_display, f->display.x->cursor_gc, f->display.x->font->fid); + frame_update_line_height (f); x_set_window_size (f, 0, f->width, f->height); } + else + /* If we are setting a new frame's font for the first time, + there are no faces yet, so this font's height is the line height. */ + f->display.x->line_height = FONT_HEIGHT (f->display.x->font); { - Lisp_Object lispy_name = build_string (fontname); + Lisp_Object lispy_name; + lispy_name = build_string (fontname); /* Free the information from XListFonts. The data we actually retain comes from XLoadQueryFont. */ @@ -4517,9 +5191,10 @@ x_calc_absolute_position (f) #endif /* ! defined (HAVE_X11) */ } -x_set_offset (f, xoff, yoff) +x_set_offset (f, xoff, yoff, change_gravity) struct frame *f; register int xoff, yoff; + int change_gravity; { f->display.x->top_pos = yoff; f->display.x->left_pos = xoff; @@ -4534,7 +5209,10 @@ x_set_offset (f, xoff, yoff) f->display.x->left_pos, f->display.x->top_pos); #endif /* not USE_X_TOOLKIT */ #ifdef HAVE_X11 - x_wm_set_size_hint (f, 0, 1, xoff, yoff); + if (change_gravity) + f->display.x->win_gravity = NorthWestGravity; + + x_wm_set_size_hint (f, 0, 1); #endif /* ! defined (HAVE_X11) */ UNBLOCK_INPUT; } @@ -4570,8 +5248,9 @@ x_set_window_size (f, change_gravity, cols, rows) pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows); #ifdef HAVE_X11 - x_wm_set_size_hint (f, 0, change_gravity, 0, 0); + x_wm_set_size_hint (f, 0, change_gravity); #endif /* ! defined (HAVE_X11) */ + XSync (x_current_display, False); XChangeWindowSize (FRAME_X_WINDOW (f), pixelwidth, pixelheight); /* Now, strictly speaking, we can't be sure that this is accurate, @@ -4607,7 +5286,7 @@ x_set_resize_hint (f) 2 * f->display.x->internal_border_width, 2 * f->display.x->internal_border_width, FONT_WIDTH (f->display.x->font), - FONT_HEIGHT (f->display.x->font)); + f->display.x->line_height); } #endif /* HAVE_X11 */ @@ -4624,7 +5303,7 @@ x_set_mouse_position (f, x, y) #endif pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH (f->display.x->font) / 2; - pix_y = CHAR_TO_PIXEL_ROW (f, y) + FONT_HEIGHT (f->display.x->font) / 2; + pix_y = CHAR_TO_PIXEL_ROW (f, y) + f->display.x->line_height / 2; if (pix_x < 0) pix_x = 0; if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f); @@ -4727,6 +5406,8 @@ x_make_frame_visible (f) if (! FRAME_VISIBLE_P (f)) { #ifdef HAVE_X11 + x_set_offset (f, f->display.x->top_pos, f->display.x->left_pos, 0); + if (! EQ (Vx_no_window_manager, Qt)) x_wm_set_window_state (f, NormalState); #ifdef USE_X_TOOLKIT @@ -4734,8 +5415,12 @@ x_make_frame_visible (f) #else /* not USE_X_TOOLKIT */ XMapWindow (XDISPLAY FRAME_X_WINDOW (f)); #endif /* not USE_X_TOOLKIT */ +#if 0 /* This seems to bring back scroll bars in the wrong places + if the window configuration has changed. They seem + to come back ok without this. */ if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)) XMapSubwindows (x_current_display, FRAME_X_WINDOW (f)); +#endif #else /* ! defined (HAVE_X11) */ XMapWindow (XDISPLAY FRAME_X_WINDOW (f)); if (f->display.x->icon_desc != 0) @@ -4900,8 +5585,10 @@ x_iconify_frame (f) { /* If the frame was withdrawn, before, we must map it. */ XMapWindow (XDISPLAY FRAME_X_WINDOW (f)); +#if 0 /* We don't have subwindows in the icon. */ if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)) XMapSubwindows (x_current_display, FRAME_X_WINDOW (f)); +#endif } f->async_iconified = 1; @@ -4946,6 +5633,13 @@ x_destroy_window (f) if (f == x_highlight_frame) x_highlight_frame = 0; + if (f == mouse_face_mouse_frame) + { + mouse_face_beg = -1; + mouse_face_end = -1; + mouse_face_window = Qnil; + } + UNBLOCK_INPUT; } @@ -5027,23 +5721,21 @@ mouse_event_pending_p () #ifdef HAVE_X11 -/* Record the gravity used previously, in case CHANGE_GRAVITY is 0. */ -static int previous_gravity; - /* SPEC_X and SPEC_Y are the specified positions. We look only at their sign, to decide the gravity. - If CHANGE_GRAVITY is 0, we ignore SPEC_X and SPEC_Y - and leave the gravity unchanged. */ + If CHANGE_GRAVITY is 0, we may set PWinGravity. */ -x_wm_set_size_hint (f, prompting, change_gravity, spec_x, spec_y) +x_wm_set_size_hint (f, prompting, change_gravity) struct frame *f; long prompting; int change_gravity; - int spec_x, spec_y; { XSizeHints size_hints; #ifdef USE_X_TOOLKIT + Arg al[2]; + int ac = 0; + Dimension widget_width, widget_height; Window window = XtWindow (f->display.x->widget); #else /* not USE_X_TOOLKIT */ Window window = FRAME_X_WINDOW (f); @@ -5055,46 +5747,48 @@ x_wm_set_size_hint (f, prompting, change_gravity, spec_x, spec_y) size_hints.x = f->display.x->left_pos; size_hints.y = f->display.x->top_pos; +#ifdef USE_X_TOOLKIT + XtSetArg (al[ac], XtNwidth, &widget_width); ac++; + XtSetArg (al[ac], XtNheight, &widget_height); ac++; + XtGetValues (f->display.x->column_widget, al, ac); + size_hints.height = widget_height; + size_hints.width = widget_width; +#else /* not USE_X_TOOLKIT */ size_hints.height = PIXEL_HEIGHT (f); size_hints.width = PIXEL_WIDTH (f); +#endif /* not USE_X_TOOLKIT */ size_hints.width_inc = FONT_WIDTH (f->display.x->font); - size_hints.height_inc = FONT_HEIGHT (f->display.x->font); -#if 0 - size_hints.max_width = x_screen_width - CHAR_TO_PIXEL_WIDTH (f, 0); - size_hints.max_height = x_screen_height - CHAR_TO_PIXEL_HEIGHT (f, 0); -#endif + size_hints.height_inc = f->display.x->line_height; + { int base_width, base_height; + int min_rows = 0, min_cols = 0; base_width = CHAR_TO_PIXEL_WIDTH (f, 0); base_height = CHAR_TO_PIXEL_HEIGHT (f, 0); - { - int min_rows = 0, min_cols = 0; - check_frame_size (f, &min_rows, &min_cols); - - /* The window manager uses the base width hints to calculate the - current number of rows and columns in the frame while - resizing; min_width and min_height aren't useful for this - purpose, since they might not give the dimensions for a - zero-row, zero-column frame. + check_frame_size (f, &min_rows, &min_cols); - We use the base_width and base_height members if we have - them; otherwise, we set the min_width and min_height members - to the size for a zero x zero frame. */ + /* The window manager uses the base width hints to calculate the + current number of rows and columns in the frame while + resizing; min_width and min_height aren't useful for this + purpose, since they might not give the dimensions for a + zero-row, zero-column frame. + + We use the base_width and base_height members if we have + them; otherwise, we set the min_width and min_height members + to the size for a zero x zero frame. */ #ifdef HAVE_X11R4 - size_hints.flags |= PBaseSize; - size_hints.base_width = base_width; - size_hints.base_height = base_height; - size_hints.min_width = base_width + min_cols * size_hints.width_inc; - size_hints.min_height = base_height + min_rows * size_hints.height_inc; + size_hints.flags |= PBaseSize; + size_hints.base_width = base_width; + size_hints.base_height = base_height; + size_hints.min_width = base_width + min_cols * size_hints.width_inc; + size_hints.min_height = base_height + min_rows * size_hints.height_inc; #else - size_hints.min_width = base_width; - size_hints.min_height = base_height; + size_hints.min_width = base_width; + size_hints.min_height = base_height; #endif - } - } if (prompting) @@ -5114,30 +5808,15 @@ x_wm_set_size_hint (f, prompting, change_gravity, spec_x, spec_y) if (hints.flags & USSize) size_hints.flags |= USSize; } + + size_hints.win_gravity = f->display.x->win_gravity; + #if defined (PWinGravity) if (change_gravity) { - switch (((spec_x < 0) << 1) + (spec_y < 0)) - { - case 0: - size_hints.win_gravity = NorthWestGravity; - break; - case 1: - size_hints.win_gravity = NorthEastGravity; - break; - case 2: - size_hints.win_gravity = SouthWestGravity; - break; - case 3: - size_hints.win_gravity = SouthEastGravity; - break; - } - previous_gravity = size_hints.win_gravity; + if (! (size_hints.flags & USPosition)) + size_hints.flags |= PWinGravity; } - else - size_hints.win_gravity = previous_gravity; - - size_hints.flags |= PWinGravity; #endif /* PWinGravity */ #ifdef HAVE_X11R4 @@ -5316,6 +5995,7 @@ Check the DISPLAY environment variable or use \"-d\"\n", update_end_hook = XTupdate_end; set_terminal_window_hook = XTset_terminal_window; read_socket_hook = XTread_socket; + frame_up_to_date_hook = XTframe_up_to_date; cursor_to_hook = XTcursor_to; reassert_line_highlight_hook = XTreassert_line_highlight; mouse_position_hook = XTmouse_position; @@ -5355,6 +6035,8 @@ syms_of_xterm () { staticpro (&last_mouse_scroll_bar); last_mouse_scroll_bar = Qnil; + staticpro (&mouse_face_window); + mouse_face_window = Qnil; } #endif /* ! defined (HAVE_X11) */ #endif /* ! defined (HAVE_X_WINDOWS) */