X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/1113d9db4b32832799c1e686900d5655d5d3e5ba..0114e17e668a921c9050d5743943c16a9cee5f37:/src/xterm.c diff --git a/src/xterm.c b/src/xterm.c index 7bf039a1cf..c6fd73c13b 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, 1992 Free Software Foundation, Inc. + Copyright (C) 1989, 1993 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -25,50 +25,47 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ */ +#define NEW_SELECTIONS + +/* On 4.3 these lose if they come after xterm.h. */ +/* On HP-UX 8.0 signal.h loses if it comes after config.h. */ +/* Putting these at the beginning seems to be standard for other .c files. */ +#include +#include + #include "config.h" #ifdef HAVE_X_WINDOWS #include "lisp.h" - -/* On 4.3 this loses if it comes after xterm.h. */ -#include +#include "blockinput.h" /* This may include sys/types.h, and that somehow loses if this is not done before the other system files. */ #include "xterm.h" +#include +#ifndef USG /* Load sys/types.h if not already loaded. In some systems loading it twice is suicidal. */ #ifndef makedev #include -#endif +#endif /* makedev */ +#endif /* USG */ #ifdef BSD #include #include -#else -#include +#else /* ! defined (BSD) */ +#ifndef VMS #include #endif +#endif /* ! defined (BSD) */ -/* Allow m- file to inhibit use of FIONREAD. */ -#ifdef BROKEN_FIONREAD -#undef FIONREAD -#endif - -/* We are unable to use interrupts if FIONREAD is not available, - so flush SIGIO so we won't try. */ -#ifndef FIONREAD -#ifdef SIGIO -#undef SIGIO -#endif -#endif - +#include "systty.h" #include "systime.h" #include -#include #include #include #include @@ -82,18 +79,40 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #if 0 #include "sink.h" #include "sinkmask.h" -#endif +#endif /* ! 0 */ #include "gnu.h" -#include "screen.h" +#include "frame.h" #include "disptab.h" #include "buffer.h" +#include "window.h" #ifdef HAVE_X11 #define XMapWindow XMapRaised /* Raise them when mapping. */ -#else +#else /* ! defined (HAVE_X11) */ #include /*#include */ -#endif /* HAVE_X11 */ +#endif /* ! defined (HAVE_X11) */ + +#ifdef FD_SET +/* We could get this from param.h, but better not to depend on finding that. + And better not to risk that it might define other symbols used in this + file. */ +#ifdef FD_SETSIZE +#define MAXDESC FD_SETSIZE +#else +#define MAXDESC 64 +#endif +#define SELECT_TYPE fd_set +#else /* no FD_SET */ +#define MAXDESC 32 +#define SELECT_TYPE int + +/* Define the macros to access a single-int bitmap of descriptors. */ +#define FD_SET(n, p) (*(p) |= (1 << (n))) +#define FD_CLR(n, p) (*(p) &= ~(1 << (n))) +#define FD_ISSET(n, p) (*(p) & (1 << (n))) +#define FD_ZERO(p) (*(p) = 0) +#endif /* no FD_SET */ /* For sending Meta-characters. Do we need this? */ #define METABIT 0200 @@ -103,8 +122,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Nonzero means we must reprint all windows because 1) we received an ExposeWindow event - or 2) we received too many ExposeRegion events to record. */ + or 2) we received too many ExposeRegion events to record. + This is never needed under X11. */ static int expose_all_windows; /* Nonzero means we must reprint all icon windows. */ @@ -121,25 +141,11 @@ static struct event_queue x_expose_queue; are copied into this queue for later processing. */ struct event_queue x_mouse_queue; -#endif - -/* Nonzero after BLOCK_INPUT; prevents input events from being - processed until later. */ - -int x_input_blocked; +#endif /* HAVE_X11 */ #if defined (SIGIO) && defined (FIONREAD) int BLOCK_INPUT_mask; -#endif - -/* Nonzero if input events came in while x_input_blocked was nonzero. - UNBLOCK_INPUT checks for this. */ - -int x_pending_input; - -/* Nonzero if in redisplay (); prevents us from calling it recursively */ - -int in_display; +#endif /* ! defined (SIGIO) && defined (FIONREAD) */ /* The id of a bitmap used for icon windows. One such map is shared by all Emacs icon windows. @@ -155,33 +161,43 @@ static FONT_TYPE *icon_font_info; extern Lisp_Object Vcommand_line_args; char *hostname, *x_id_name; -Lisp_Object invocation_name; /* This is the X connection that we are using. */ Display *x_current_display; -/* Screen being updated by update_screen. */ -/* This is set by XTupdate_begin and looked at by all the - XT functions. It is zero while not inside an update. - In that case, the XT functions assume that `selected_screen' - is the screen to apply to. */ - -static struct screen *updating_screen; - -/* The screen (if any) which has the X window that has keyboard focus. - Zero if none. This is examined by Ffocus_screen in screen.c. */ -struct screen *x_focus_screen; +/* The cursor to use for vertical scroll bars on x_current_display. */ +static Cursor x_vertical_scroll_bar_cursor; -/* The screen which currently has the visual highlight, and should get - keyboard input (other sorts of input have the screen encoded in the - event). It points to the X focus screen's selected window's - screen. It differs from x_focus_screen when we're using a global +/* Frame being updated by update_frame. This is declared in term.c. + This is set by update_begin and looked at by all the + XT functions. It is zero while not inside an update. + In that case, the XT functions assume that `selected_frame' + is the frame to apply to. */ +extern struct frame *updating_frame; + +/* The frame (if any) which has the X window that has keyboard focus. + Zero if none. This is examined by Ffocus_frame in frame.c. Note + that a mere EnterNotify event can set this; if you need to know the + last frame specified in a FocusIn or FocusOut event, use + x_focus_event_frame. */ +struct frame *x_focus_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 + received a FocusIn event for it. */ +struct frame *x_focus_event_frame; + +/* The frame which currently has the visual highlight, and should get + keyboard input (other sorts of input have the frame encoded in the + event). It points to the X focus frame's selected window's + frame. It differs from x_focus_frame when we're using a global minibuffer. */ -static struct screen *x_highlight_screen; +static struct frame *x_highlight_frame; /* From .Xdefaults, the value of "emacs.WarpMouse". If non-zero, - mouse is moved to inside of screen when screen is de-iconified. */ + mouse is moved to inside of frame when frame is de-iconified. */ static int warp_mouse_on_deiconify; @@ -217,7 +233,7 @@ extern Window requestor_window; /* Nonzero enables some debugging for the X interface code. */ extern int _Xdebug; -#else /* X10 stuff */ +#else /* ! defined (HAVE_X11) */ /* Bit patterns for the mouse cursor. */ @@ -237,7 +253,7 @@ static short grey_bits[] = { 0x0005, 0x000a, 0x0005, 0x000a}; static Pixmap GreyPixmap = 0; -#endif /* X10 stuff */ +#endif /* ! defined (HAVE_X11) */ /* From time to time we get info on an Emacs window, here. */ @@ -245,6 +261,9 @@ static WINDOWINFO_TYPE windowinfo; extern int errno; +/* A mask of extra modifier bits to put into every keyboard char. */ +extern int extra_keyboard_modifiers; + extern Display *XOpenDisplay (); extern Window XCreateWindow (); @@ -252,66 +271,69 @@ extern Cursor XCreateCursor (); extern FONT_TYPE *XOpenFont (); static void flashback (); +static void redraw_previous_char (); #ifndef HAVE_X11 static void dumpqueue (); -#endif +#endif /* HAVE_X11 */ void dumpborder (); static int XTcursor_to (); static int XTclear_end_of_line (); + -/* These hooks are called by update_screen at the beginning and end - of a screen update. We record in `updating_screen' the identity - of the screen being updated, so that the XT... functions do not - need to take a screen as argument. Most of the XT... functions +/* Starting and ending updates. + + These hooks are called by update_frame at the beginning and end + of a frame update. We record in `updating_frame' the identity + of the frame being updated, so that the XT... functions do not + need to take a frame as argument. Most of the XT... functions should never be called except during an update, the only exceptions - being XTcursor_to, XTwrite_char and XTreassert_line_highlight. */ + being XTcursor_to, XTwrite_glyphs and XTreassert_line_highlight. */ extern int mouse_track_top, mouse_track_left, mouse_track_width; static -XTupdate_begin (s) - struct screen *s; +XTupdate_begin (f) + struct frame *f; { int mask; - if (s == 0) + if (f == 0) abort (); - updating_screen = s; - flexlines = s->height; + flexlines = f->height; highlight = 0; BLOCK_INPUT; #ifndef HAVE_X11 dumpqueue (); -#endif +#endif /* HAVE_X11 */ UNBLOCK_INPUT; } +#ifndef HAVE_X11 static void x_do_pending_expose (); +#endif static -XTupdate_end (s) - struct screen *s; +XTupdate_end (f) + struct frame *f; { int mask; - if (updating_screen == 0 - || updating_screen != s) + if (updating_frame == 0 + || updating_frame != f) abort (); BLOCK_INPUT; #ifndef HAVE_X11 dumpqueue (); -#endif - adjust_scrollbars (s); x_do_pending_expose (); +#endif /* HAVE_X11 */ - x_display_cursor (s, 1); + x_display_cursor (f, 1); - updating_screen = 0; XFlushQueue (); UNBLOCK_INPUT; } @@ -335,7 +357,7 @@ XTchange_line_highlight (new_highlight, vpos, first_unused_hpos) { highlight = new_highlight; XTcursor_to (vpos, 0); - XTclear_end_of_line (updating_screen->width); + XTclear_end_of_line (updating_frame->width); } /* This is used when starting Emacs and when restarting after suspend. @@ -354,11 +376,11 @@ XTset_terminal_modes () static XTreset_terminal_modes () { -/* XTclear_screen (); */ +/* XTclear_frame (); */ } -/* Set the nominal cursor position of the screen: - where display update commands will take effect. +/* Set the nominal cursor position of the frame. + This is where display update commands will take effect. This does not affect the place where the cursor-box is displayed. */ static int @@ -371,10 +393,10 @@ XTcursor_to (row, col) curs_x = col; curs_y = row; - if (updating_screen == 0) + if (updating_frame == 0) { BLOCK_INPUT; - x_display_cursor (selected_screen, 1); + x_display_cursor (selected_frame, 1); XFlushQueue (); UNBLOCK_INPUT; } @@ -384,65 +406,40 @@ XTcursor_to (row, col) 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. - FONT is the default font to use (for glyphs whose font-code is 0). */ + FONT is the default font to use (for glyphs whose font-code is 0). -static void -dumpglyphs (s, left, top, gp, n, hl, font) - struct screen *s; - int left, top; - register GLYPH *gp; /* Points to first GLYPH. */ - register int n; /* Number of glyphs to display. */ - int hl; - FONT_TYPE *font; -{ - register int len; - Window window = s->display.x->window_desc; - GC drawing_gc = (hl == 2 ? s->display.x->cursor_gc - : (hl ? s->display.x->reverse_gc - : s->display.x->normal_gc)); + Since the display generation code is responsible for calling + compute_char_face and compute_glyph_face on everything it puts in + the display structure, we can assume that the face code on each + glyph is a valid index into FRAME_COMPUTED_FACES (f), and the one + to which we can actually apply intern_face. */ - if (sizeof (GLYPH) == sizeof (XChar2b)) - XDrawImageString16 (x_current_display, window, drawing_gc, - left, top + FONT_BASE (font), (XChar2b *) gp, n); - else if (sizeof (GLYPH) == sizeof (unsigned char)) - XDrawImageString (x_current_display, window, drawing_gc, - left, top + FONT_BASE (font), (char *) gp, n); - else - /* What size of glyph ARE you using? And does X have a function to - draw them? */ - abort (); -} +#if 1 +/* This is the multi-face code. */ -#if 0 static void -dumpglyphs (s, left, top, gp, n, hl, font) - struct screen *s; +dumpglyphs (f, left, top, gp, n, hl) + struct frame *f; int left, top; register GLYPH *gp; /* Points to first GLYPH. */ register int n; /* Number of glyphs to display. */ int hl; - FONT_TYPE *font; { - char buf[s->width]; /* Holds characters to be displayed. */ + /* Holds characters to be displayed. */ + char *buf = (char *) alloca (f->width * sizeof (*buf)); register char *cp; /* Steps through buf[]. */ register int tlen = GLYPH_TABLE_LENGTH; register Lisp_Object *tbase = GLYPH_TABLE_BASE; - Window window = s->display.x->window_desc; - int cursor_pixel = s->display.x->cursor_pixel; - int fg_pixel = s->display.x->foreground_pixel; - int bg_pixel = s->display.x->background_pixel; - int intborder = s->display.x->internal_border_width; + Window window = FRAME_X_WINDOW (f); - while (n) + while (n > 0) { /* Get the face-code of the next GLYPH. */ int cf, len; int g = *gp; - while (GLYPH_ALIAS_P (tbase, tlen, g)) - g = GLYPH_ALIAS (tbase, g); - - cf = g >> 8; + GLYPH_FOLLOW_ALIASES (tbase, tlen, g); + cf = GLYPH_FACE (g); /* Find the run of consecutive glyphs with the same face-code. Extract their character codes into BUF. */ @@ -450,12 +447,11 @@ dumpglyphs (s, left, top, gp, n, hl, font) while (n > 0) { g = *gp; - while (GLYPH_ALIAS_P (tbase, tlen, g)) - g = GLYPH_ALIAS (tbase, g); - if ((g >> 8) != cf) + GLYPH_FOLLOW_ALIASES (tbase, tlen, g); + if (GLYPH_FACE (g) != cf) break; - *cp++ = 0377 & g; + *cp++ = GLYPH_CHAR (g); --n; ++gp; } @@ -465,68 +461,140 @@ dumpglyphs (s, left, top, gp, n, hl, font) /* Now output this run of chars, with the font and pixel values determined by the face code CF. */ - if (cf == 0) - { -#ifdef HAVE_X11 - GC GC_cursor = s->display.x->cursor_gc; - GC GC_reverse = s->display.x->reverse_gc; - GC GC_normal = s->display.x->normal_gc; - - XDrawImageString (x_current_display, window, - (hl == 2 - ? GC_cursor - : (hl ? GC_reverse : GC_normal)), - left, top + FONT_BASE (font), buf, len); -#else - XText (window, left, top, - buf, - len, - font->id, - (hl == 2 - ? (cursor_pixel == fg_pixel ? bg_pixel : fg_pixel) - : hl ? bg_pixel : fg_pixel), - (hl == 2 ? cursor_pixel - : hl ? fg_pixel : bg_pixel)); -#endif /* HAVE_X11 */ - } - else + { + 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; + + /* First look at the face of the text itself. */ + if (cf != 0) + { + /* The face codes on the glyphs must be valid indices into the + frame's face table. */ + if (cf < 0 || cf >= FRAME_N_COMPUTED_FACES (f) + || FRAME_COMPUTED_FACES (f) [cf] == 0) + abort (); + + if (cf == 1) + face = FRAME_MODE_LINE_FACE (f); + else + 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. */ + else if (hl == 0) + ; + else if (hl == 1) + { + face = FRAME_MODE_LINE_FACE (f); + font = FACE_FONT (face); + gc = FACE_GC (face); + defaulted = 0; + } + +#define FACE_DEFAULT (~0) + + /* Now override that if the cursor's on this character. */ + if (hl == 2) + { + if (defaulted + || !face->font + || (int) face->font == FACE_DEFAULT) + { + gc = f->display.x->cursor_gc; + } + /* Cursor on non-default face: must merge. */ + else + { + XGCValues xgcv; + unsigned long mask; + + xgcv.background = f->display.x->cursor_pixel; + xgcv.foreground = f->display.x->cursor_foreground_pixel; + xgcv.font = face->font->fid; + xgcv.graphics_exposures = 0; + mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures; + gc = XCreateGC (x_current_display, FRAME_X_WINDOW (f), + mask, &xgcv); +#if 0 + if (face->stipple && face->stipple != FACE_DEFAULT) + XSetStipple (x_current_display, gc, face->stipple); +#endif + gc_temporary = 1; + } + } + + if ((int) font == FACE_DEFAULT) + font = f->display.x->font; + + XDrawImageString (x_current_display, window, gc, + left, top + FONT_BASE (font), buf, len); + + if (gc_temporary) + XFreeGC (x_current_display, gc); + + /* We should probably check for XA_UNDERLINE_POSITION and + XA_UNDERLINE_THICKNESS properties on the font, but let's + just get the thing working, and come back to that. */ { -#ifdef HAVE_X11 - if (FACE_IS_FONT (cf)) - XDrawImageString (x_current_display, s->display.x->window_desc, - FACE_GC (cf), - left, top + FONT_BASE (FACE_FONT (cf)), - buf, len); - else if (FACE_IS_IMAGE (cf)) - XCopyPlane (x_current_display, FACE_IMAGE (cf), - s->display.x->window_desc, - s->display.x->normal_gc, - 0, 0, - FACE_IMAGE_WIDTH (cf), - FACE_IMAGE_HEIGHT (cf), left, top); - else - abort (); -#else - register struct face *fp = x_face_table[cf]; - - XText (window, left, top, - buf, - len, - fp->font->id, - (hl == 2 - ? (cursor_pixel == fp->fg ? fp->bg : fp->fg) - : hl ? fp->bg : fp->fg), - (hl == 2 ? cursor_pixel - : hl ? fp->fg : fp->bg)); -#endif /* HAVE_X11 */ + int underline_position = 1; + + if (font->descent <= underline_position) + underline_position = font->descent - 1; + + if (face->underline) + XFillRectangle (x_current_display, FRAME_X_WINDOW (f), + FACE_GC (face), + left, (top + + FONT_BASE (font) + + underline_position), + len * FONT_WIDTH (font), 1); } - left += len * FONT_WIDTH (font); + + left += len * FONT_WIDTH (font); + } } } +#endif /* 1 */ + +#if 0 +/* This is the old single-face code. */ + +static void +dumpglyphs (f, left, top, gp, n, hl, font) + struct frame *f; + int left, top; + register GLYPH *gp; /* Points to first GLYPH. */ + register int n; /* Number of glyphs to display. */ + int hl; + FONT_TYPE *font; +{ + register int len; + Window window = FRAME_X_WINDOW (f); + GC drawing_gc = (hl == 2 ? f->display.x->cursor_gc + : (hl ? f->display.x->reverse_gc + : f->display.x->normal_gc)); + + if (sizeof (GLYPH) == sizeof (XChar2b)) + XDrawImageString16 (x_current_display, window, drawing_gc, + left, top + FONT_BASE (font), (XChar2b *) gp, n); + else if (sizeof (GLYPH) == sizeof (unsigned char)) + XDrawImageString (x_current_display, window, drawing_gc, + left, top + FONT_BASE (font), (char *) gp, n); + else + /* What size of glyph ARE you using? And does X have a function to + draw them? */ + abort (); +} #endif -/* Output some text at the nominal screen cursor position, - advancing the cursor over the text. +/* Output some text at the nominal frame cursor position. + Advance the cursor over the text. Output LEN glyphs at START. `highlight', set up by XTreassert_line_highlight or XTchange_line_highlight, @@ -539,38 +607,36 @@ XTwrite_glyphs (start, len) { register int temp_length; int mask; - struct screen *s; + struct frame *f; BLOCK_INPUT; - s = updating_screen; - if (s == 0) + f = updating_frame; + if (f == 0) { - s = selected_screen; + f = selected_frame; /* If not within an update, - output at the screen's visible cursor. */ - curs_x = s->cursor_x; - curs_y = s->cursor_y; + output at the frame's visible cursor. */ + curs_x = f->cursor_x; + curs_y = f->cursor_y; } - dumpglyphs (s, - (curs_x * FONT_WIDTH (s->display.x->font) - + s->display.x->internal_border_width), - (curs_y * FONT_HEIGHT (s->display.x->font) - + s->display.x->internal_border_width), - start, len, highlight, s->display.x->font); + dumpglyphs (f, + CHAR_TO_PIXEL_COL (f, curs_x), + CHAR_TO_PIXEL_ROW (f, curs_y), + start, len, highlight); /* If we drew on top of the cursor, note that it is turned off. */ - if (curs_y == s->phys_cursor_y - && curs_x <= s->phys_cursor_x - && curs_x + len > s->phys_cursor_x) - s->phys_cursor_x = -1; + if (curs_y == f->phys_cursor_y + && curs_x <= f->phys_cursor_x + && curs_x + len > f->phys_cursor_x) + f->phys_cursor_x = -1; - if (updating_screen == 0) + if (updating_frame == 0) { - s->cursor_x += len; - x_display_cursor (s, 1); - s->cursor_x -= len; + f->cursor_x += len; + x_display_cursor (f, 1); + f->cursor_x -= len; } else curs_x += len; @@ -578,7 +644,8 @@ XTwrite_glyphs (start, len) UNBLOCK_INPUT; } -/* Erase the current text line from the nominal cursor position (inclusive) +/* Clear to the end of the line. + Erase the current text line from the nominal cursor position (inclusive) to column FIRST_UNUSED (exclusive). The idea is that everything from FIRST_UNUSED onward is already erased. */ @@ -586,171 +653,235 @@ static int XTclear_end_of_line (first_unused) register int first_unused; { - struct screen *s = updating_screen; + struct frame *f = updating_frame; int mask; - if (s == 0) + if (f == 0) abort (); - if (curs_y < 0 || curs_y >= s->height) + if (curs_y < 0 || curs_y >= f->height) return; if (first_unused <= 0) return; - if (first_unused >= s->width) - first_unused = s->width; + if (first_unused >= f->width) + first_unused = f->width; BLOCK_INPUT; /* Notice if the cursor will be cleared by this operation. */ - if (curs_y == s->phys_cursor_y - && curs_x <= s->phys_cursor_x - && s->phys_cursor_x < first_unused) - s->phys_cursor_x = -1; + if (curs_y == f->phys_cursor_y + && curs_x <= f->phys_cursor_x + && f->phys_cursor_x < first_unused) + f->phys_cursor_x = -1; #ifdef HAVE_X11 - XClearArea (x_current_display, s->display.x->window_desc, - curs_x * FONT_WIDTH (s->display.x->font) - + s->display.x->internal_border_width, - curs_y * FONT_HEIGHT (s->display.x->font) - + s->display.x->internal_border_width, - FONT_WIDTH (s->display.x->font) * (first_unused - curs_x), - FONT_HEIGHT (s->display.x->font), False); - -#else - XPixSet (s->display.x->window_desc, - curs_x * FONT_WIDTH (s->display.x->font) + s->display.x->internal_border_width, - curs_y * FONT_HEIGHT (s->display.x->font) + s->display.x->internal_border_width, - FONT_WIDTH (s->display.x->font) * (first_unused - curs_x), - FONT_HEIGHT (s->display.x->font), - s->display.x->background_pixel); -#endif /* HAVE_X11 */ + XClearArea (x_current_display, 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), False); +#if 0 + redraw_previous_char (f, curs_x, curs_y); +#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->background_pixel); +#endif /* ! defined (HAVE_X11) */ UNBLOCK_INPUT; } +/* 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, + in case the character after X overlaps into the one before X. */ + +static void +redraw_previous_char (f, x, y) + FRAME_PTR f; + int x, y; +{ + /* Erase the character before the new ones, in case + what was here before overlaps it. + Reoutput that character, and the previous character + (in case the previous character overlaps it). */ + if (x > 0) + { + int start_x = x - 2; + if (start_x < 0) + start_x = 0; + XClearArea (x_current_display, FRAME_X_WINDOW (f), + 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); + + 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); + } +} + static -XTclear_screen () +XTclear_frame () { int mask; - struct screen *s = updating_screen; + struct frame *f = updating_frame; - if (s == 0) - s = selected_screen; + if (f == 0) + f = selected_frame; - s->phys_cursor_x = -1; /* Cursor not visible. */ + f->phys_cursor_x = -1; /* Cursor not visible. */ curs_x = 0; /* Nominal cursor position is top left. */ curs_y = 0; BLOCK_INPUT; - XClear (s->display.x->window_desc); + + 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 (s, 0); -#endif + dumpborder (f, 0); +#endif /* HAVE_X11 */ + XFlushQueue (); UNBLOCK_INPUT; } -/* Paint horzontal bars down the screen for a visible bell. - Note that this may be way too slow on some machines. */ +/* Invert the middle quarter of the frame for .15 sec. */ -XTflash (s) - struct screen *s; -{ - register struct screen_glyphs *active_screen = SCREEN_CURRENT_GLYPHS (s); - register int i; - int x, y; +/* We use the select system call to do the waiting, so we have to make sure + it's available. If it isn't, we just won't do visual bells. */ +#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) - if (updating_screen != 0) - abort (); +/* Subtract the `struct timeval' values X and Y, + storing the result in RESULT. + Return 1 if the difference is negative, otherwise 0. */ - BLOCK_INPUT; -#ifdef HAVE_X11 -#if 0 - for (i = s->height * FONT_HEIGHT (s->display.x->font) - 10; - i >= 0; - i -= 100) /* Should be NO LOWER than 75 for speed reasons. */ - XFillRectangle (x_current_display, s->display.x->window_desc, - s->display.x->cursor_gc, - 0, i, s->width * FONT_WIDTH (s->display.x->font) - + 2 * s->display.x->internal_border_width, 25); -#endif +static int +timeval_subtract (result, x, y) + struct timeval *result, x, y; +{ + /* Perform the carry for the later subtraction by updating y. + This is safer because on some systems + the tv_sec member is unsigned. */ + if (x.tv_usec < y.tv_usec) + { + int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1; + y.tv_usec -= 1000000 * nsec; + y.tv_sec += nsec; + } + if (x.tv_usec - y.tv_usec > 1000000) + { + int nsec = (y.tv_usec - x.tv_usec) / 1000000; + y.tv_usec += 1000000 * nsec; + y.tv_sec -= nsec; + } - x = (s->width * FONT_WIDTH (s->display.x->font)) / 4; - y = (s->height * FONT_HEIGHT (s->display.x->font)) / 4; - XFillRectangle (x_current_display, s->display.x->window_desc, - s->display.x->cursor_gc, - x, y, 2 * x, 2 * y); - dumpglyphs (s, (x + s->display.x->internal_border_width), - (y + s->display.x->internal_border_width), - &active_screen->glyphs[(s->height / 4) + 1][(s->width / 4)], - 1, 0, s->display.x->font); - -#else /* X10 */ - for (i = s->height * FONT_HEIGHT (s->display.x->font) - 10; - i >= 0; - i -= 50) - XPixFill (s->display.x->window_desc, 0, i, - s->width * FONT_WIDTH (s->display.x->font) - + 2 * s->display.x->internal_border_width, 10, - WHITE_PIX_DEFAULT, ClipModeClipped, GXinvert, AllPlanes); -#endif /* X10 */ + /* Compute the time remaining to wait. tv_usec is certainly positive. */ + result->tv_sec = x.tv_sec - y.tv_sec; + result->tv_usec = x.tv_usec - y.tv_usec; - XFlushQueue (); - UNBLOCK_INPUT; + /* Return indication of whether the result should be considered negative. */ + return x.tv_sec < y.tv_sec; } -/* Flip background and forground colors of the screen. */ - -x_invert_screen (s) - struct screen *s; +XTflash (f) + struct frame *f; { -#ifdef HAVE_X11 - GC temp; - unsigned long pix_temp; + BLOCK_INPUT; + + { + GC gc; + + /* Create a GC that will use the GXxor function to flip foreground pixels + into background pixels. */ + { + XGCValues values; - x_display_cursor (s, 0); - XClearWindow (x_current_display, s->display.x->window_desc); - temp = s->display.x->normal_gc; - s->display.x->normal_gc = s->display.x->reverse_gc; - s->display.x->reverse_gc = temp; - pix_temp = s->display.x->foreground_pixel; - s->display.x->foreground_pixel = s->display.x->background_pixel; - s->display.x->background_pixel = pix_temp; + values.function = GXxor; + values.foreground = (f->display.x->foreground_pixel + ^ f->display.x->background_pixel); + + gc = XCreateGC (x_current_display, FRAME_X_WINDOW (f), + GCFunction | GCForeground, &values); + } - XSetWindowBackground (x_current_display, s->display.x->window_desc, - s->display.x->background_pixel); - if (s->display.x->background_pixel == s->display.x->cursor_pixel) { - s->display.x->cursor_pixel = s->display.x->foreground_pixel; - XSetBackground (x_current_display, s->display.x->cursor_gc, - s->display.x->cursor_pixel); - XSetForeground (x_current_display, s->display.x->cursor_gc, - s->display.x->background_pixel); + int width = PIXEL_WIDTH (f); + int height = PIXEL_HEIGHT (f); + + XFillRectangle (x_current_display, FRAME_X_WINDOW (f), gc, + width/4, height/4, width/2, height/2); + XFlush (x_current_display); + + { + struct timeval wakeup, now; + + gettimeofday (&wakeup, (struct timezone *) 0); + + /* Compute time to wait until, propagating carry from usecs. */ + wakeup.tv_usec += 150000; + wakeup.tv_sec += (wakeup.tv_usec / 1000000); + wakeup.tv_usec %= 1000000; + + /* Keep waiting until past the time wakeup. */ + while (1) + { + struct timeval timeout; + + gettimeofday (&timeout, (struct timezone *)0); + + /* In effect, timeout = wakeup - timeout. + Break if result would be negative. */ + if (timeval_subtract (&timeout, wakeup, timeout)) + break; + + /* Try to wait that long--but we might wake up sooner. */ + select (0, 0, 0, 0, &timeout); + } + } + + XFillRectangle (x_current_display, FRAME_X_WINDOW (f), gc, + width/4, height/4, width/2, height/2); + XFreeGC (x_current_display, gc); + XFlush (x_current_display); } - redraw_screen (s); -#endif /* X11 */ + } + + UNBLOCK_INPUT; } +#endif + + /* Make audible bell. */ #ifdef HAVE_X11 #define XRINGBELL XBell(x_current_display, 0) -#else +#else /* ! defined (HAVE_X11) */ #define XRINGBELL XFeep(0); -#endif +#endif /* ! defined (HAVE_X11) */ XTring_bell () { + if (x_current_display == 0) + return; + +#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) if (visible_bell) -#if 0 - XTflash (selected_screen); -#endif - { - x_invert_screen (selected_screen); - x_invert_screen (selected_screen); - } + XTflash (selected_frame); else +#endif { BLOCK_INPUT; XRINGBELL; @@ -759,8 +890,9 @@ XTring_bell () } } -/* Insert and delete character are not supposed to be used - because we are supposed to turn off the feature of using them. */ +/* Insert and delete character. + These are not supposed to be used because we are supposed to turn + off the feature of using them. */ static XTinsert_glyphs (start, len) @@ -786,17 +918,17 @@ static XTset_terminal_window (n) register int n; { - if (updating_screen == 0) + if (updating_frame == 0) abort (); - if ((n <= 0) || (n > updating_screen->height)) - flexlines = updating_screen->height; + if ((n <= 0) || (n > updating_frame->height)) + flexlines = updating_frame->height; else flexlines = n; } -/* Perform an insert-lines operation, inserting N lines - at a vertical position curs_y. */ +/* Perform an insert-lines operation. + Insert N lines at a vertical position curs_y. */ static void stufflines (n) @@ -804,8 +936,8 @@ stufflines (n) { register int topregion, bottomregion; register int length, newtop, mask; - register struct screen *s = updating_screen; - int intborder = s->display.x->internal_border_width; + register struct frame *f = updating_frame; + int intborder = f->display.x->internal_border_width; if (curs_y >= flexlines) return; @@ -817,29 +949,29 @@ stufflines (n) #ifndef HAVE_X11 dumpqueue (); -#endif +#endif /* HAVE_X11 */ if ((length > 0) && (newtop <= flexlines)) { #ifdef HAVE_X11 - XCopyArea (x_current_display, s->display.x->window_desc, - s->display.x->window_desc, s->display.x->normal_gc, - intborder, topregion * FONT_HEIGHT (s->display.x->font) + intborder, - s->width * FONT_WIDTH (s->display.x->font), - length * FONT_HEIGHT (s->display.x->font), intborder, - newtop * FONT_HEIGHT (s->display.x->font) + intborder); -#else - XMoveArea (s->display.x->window_desc, - intborder, topregion * FONT_HEIGHT (s->display.x->font) + intborder, - intborder, newtop * FONT_HEIGHT (s->display.x->font) + intborder, - s->width * FONT_WIDTH (s->display.x->font), - length * FONT_HEIGHT (s->display.x->font)); + XCopyArea (x_current_display, FRAME_X_WINDOW (f), + 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, + 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)); /* 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 may want to copy this area to another area. */ x_read_exposes (); -#endif /* HAVE_X11 */ +#endif /* ! defined (HAVE_X11) */ } newtop = min (newtop, (flexlines - 1)); @@ -847,18 +979,18 @@ stufflines (n) if (length > 0) { #ifdef HAVE_X11 - XClearArea (x_current_display, s->display.x->window_desc, intborder, - topregion * FONT_HEIGHT (s->display.x->font) + intborder, - s->width * FONT_WIDTH (s->display.x->font), - n * FONT_HEIGHT (s->display.x->font), False); -#else - XPixSet (s->display.x->window_desc, + 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); +#else /* ! defined (HAVE_X11) */ + XPixSet (FRAME_X_WINDOW (f), intborder, - topregion * FONT_HEIGHT (s->display.x->font) + intborder, - s->width * FONT_WIDTH (s->display.x->font), - n * FONT_HEIGHT (s->display.x->font), - s->display.x->background_pixel); -#endif /* HAVE_X11 */ + CHAR_TO_PIXEL_ROW (f, topregion), + f->width * FONT_WIDTH (f->display.x->font), + n * FONT_HEIGHT (f->display.x->font), + f->display.x->background_pixel); +#endif /* ! defined (HAVE_X11) */ } } @@ -870,66 +1002,66 @@ scraplines (n) register int n; { int mask; - register struct screen *s = updating_screen; - int intborder = s->display.x->internal_border_width; + register struct frame *f = updating_frame; + int intborder = f->display.x->internal_border_width; if (curs_y >= flexlines) return; #ifndef HAVE_X11 dumpqueue (); -#endif +#endif /* HAVE_X11 */ if ((curs_y + n) >= flexlines) { if (flexlines >= (curs_y + 1)) { #ifdef HAVE_X11 - XClearArea (x_current_display, s->display.x->window_desc, intborder, - curs_y * FONT_HEIGHT (s->display.x->font) + intborder, - s->width * FONT_WIDTH (s->display.x->font), - (flexlines - curs_y) * FONT_HEIGHT (s->display.x->font), False); -#else - XPixSet (s->display.x->window_desc, - intborder, curs_y * FONT_HEIGHT (s->display.x->font) + intborder, - s->width * FONT_WIDTH (s->display.x->font), - (flexlines - curs_y) * FONT_HEIGHT (s->display.x->font), - s->display.x->background_pixel); -#endif /* HAVE_X11 */ + 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); +#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), + f->display.x->background_pixel); +#endif /* ! defined (HAVE_X11) */ } } else { #ifdef HAVE_X11 - XCopyArea (x_current_display, s->display.x->window_desc, - s->display.x->window_desc, s->display.x->normal_gc, + XCopyArea (x_current_display, FRAME_X_WINDOW (f), + FRAME_X_WINDOW (f), f->display.x->normal_gc, intborder, - (curs_y + n) * FONT_HEIGHT (s->display.x->font) + intborder, - s->width * FONT_WIDTH (s->display.x->font), - (flexlines - (curs_y + n)) * FONT_HEIGHT (s->display.x->font), - intborder, curs_y * FONT_HEIGHT (s->display.x->font) + intborder); - XClearArea (x_current_display, s->display.x->window_desc, + 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), + intborder, CHAR_TO_PIXEL_ROW (f, curs_y)); + XClearArea (x_current_display, FRAME_X_WINDOW (f), intborder, - (flexlines - n) * FONT_HEIGHT (s->display.x->font) + intborder, - s->width * FONT_WIDTH (s->display.x->font), - n * FONT_HEIGHT (s->display.x->font), False); -#else - XMoveArea (s->display.x->window_desc, + CHAR_TO_PIXEL_ROW (f, flexlines - n), + f->width * FONT_WIDTH (f->display.x->font), + n * FONT_HEIGHT (f->display.x->font), False); +#else /* ! defined (HAVE_X11) */ + XMoveArea (FRAME_X_WINDOW (f), intborder, - (curs_y + n) * FONT_HEIGHT (s->display.x->font) + intborder, - intborder, curs_y * FONT_HEIGHT (s->display.x->font) + intborder, - s->width * FONT_WIDTH (s->display.x->font), - (flexlines - (curs_y + n)) * FONT_HEIGHT (s->display.x->font)); + 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)); /* 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 may want to copy this area to another area. */ x_read_exposes (); - XPixSet (s->display.x->window_desc, intborder, - (flexlines - n) * FONT_HEIGHT (s->display.x->font) + intborder, - s->width * FONT_WIDTH (s->display.x->font), - n * FONT_HEIGHT (s->display.x->font), s->display.x->background_pixel); -#endif /* HAVE_X11 */ + 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); +#endif /* ! defined (HAVE_X11) */ } } @@ -939,11 +1071,11 @@ scraplines (n) XTins_del_lines (vpos, n) int vpos, n; { - if (updating_screen == 0) + if (updating_frame == 0) abort (); /* Hide the cursor. */ - x_display_cursor (updating_screen, 0); + x_display_cursor (updating_frame, 0); XTcursor_to (vpos, 0); @@ -956,60 +1088,62 @@ XTins_del_lines (vpos, n) UNBLOCK_INPUT; } +/* Support routines for exposure events. */ static void clear_cursor (); -/* Output into a rectangle of an X-window (for screen S) - the characters in s->phys_lines that overlap that rectangle. +/* Output into a rectangle of an X-window (for frame F) + the characters in f->phys_lines that overlap that rectangle. TOP and LEFT are the position of the upper left corner of the rectangle. ROWS and COLS are the size of the rectangle. */ static void -dumprectangle (s, left, top, cols, rows) - struct screen *s; +dumprectangle (f, left, top, cols, rows) + struct frame *f; register int left, top, cols, rows; { - register struct screen_glyphs *active_screen = SCREEN_CURRENT_GLYPHS (s); + register struct frame_glyphs *active_frame = FRAME_CURRENT_GLYPHS (f); int cursor_cleared = 0; int bottom, right; register int y; - if (SCREEN_GARBAGED_P (s)) + if (FRAME_GARBAGED_P (f)) return; - top -= s->display.x->internal_border_width; - left -= s->display.x->internal_border_width; - /* Express rectangle as four edges, instead of position-and-size. */ bottom = top + rows; right = left + cols; #ifndef HAVE_X11 /* Window manger does this for X11. */ - /* If the rectangle includes any of the internal border area, - redisplay the border emphasis. */ - if (top < 0 || left < 0 - || bottom > s->height * FONT_HEIGHT (s->display.x->font) - || right > s->width * FONT_WIDTH (s->display.x->font)) - dumpborder (s, 0); -#endif /* HAVE_X11 */ + { + int intborder = f->display.x->internal_border_width; + + /* 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)) + dumpborder (f, 0); + } +#endif /* 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 /= FONT_HEIGHT (s->display.x->font); - left /= FONT_WIDTH (s->display.x->font); - bottom += (FONT_HEIGHT (s->display.x->font) - 1); - right += (FONT_WIDTH (s->display.x->font) - 1); - bottom /= FONT_HEIGHT (s->display.x->font); - right /= FONT_WIDTH (s->display.x->font); + top = PIXEL_TO_CHAR_ROW (f, top); + left = PIXEL_TO_CHAR_COL (f, left); + bottom += (FONT_HEIGHT (f->display.x->font) - 1); + right += (FONT_WIDTH (f->display.x->font) - 1); + bottom = PIXEL_TO_CHAR_ROW (f, bottom); + right = PIXEL_TO_CHAR_COL (f, right); /* Clip the rectangle to what can be visible. */ if (left < 0) left = 0; if (top < 0) top = 0; - if (right > s->width) - right = s->width; - if (bottom > s->height) - bottom = s->height; + if (right > f->width) + right = f->width; + if (bottom > f->height) + bottom = f->height; /* Get size in chars of the rectangle. */ cols = right - left; @@ -1021,10 +1155,10 @@ dumprectangle (s, left, top, cols, rows) /* Turn off the cursor if it is in the rectangle. We will turn it back on afterward. */ - if ((s->phys_cursor_x >= left) && (s->phys_cursor_x < right) - && (s->phys_cursor_y >= top) && (s->phys_cursor_y < bottom)) + if ((f->phys_cursor_x >= left) && (f->phys_cursor_x < right) + && (f->phys_cursor_y >= top) && (f->phys_cursor_y < bottom)) { - clear_cursor (s); + clear_cursor (f); cursor_cleared = 1; } @@ -1032,24 +1166,22 @@ dumprectangle (s, left, top, cols, rows) for (y = top; y < bottom; y++) { - GLYPH *line = &active_screen->glyphs[y][left]; + GLYPH *line = &active_frame->glyphs[y][left]; - if (! active_screen->enable[y] || left > active_screen->used[y]) + if (! active_frame->enable[y] || left > active_frame->used[y]) continue; - dumpglyphs (s, - (left * FONT_WIDTH (s->display.x->font) - + s->display.x->internal_border_width), - (y * FONT_HEIGHT (s->display.x->font) - + s->display.x->internal_border_width), - line, min (cols, active_screen->used[y] - left), - active_screen->highlight[y], s->display.x->font); + dumpglyphs (f, + CHAR_TO_PIXEL_COL (f, left), + CHAR_TO_PIXEL_ROW (f, y), + line, min (cols, active_frame->used[y] - left), + active_frame->highlight[y]); } /* Turn the cursor on if we turned it off. */ if (cursor_cleared) - x_display_cursor (s, 1); + x_display_cursor (f, 1); } #ifndef HAVE_X11 @@ -1063,71 +1195,72 @@ dumpqueue () while (dequeue_event (&r, &x_expose_queue)) { - struct screen *s = x_window_to_screen (r.window); - if (s->display.x->icon_desc == r.window) - refreshicon (s); + struct frame *f = x_window_to_frame (r.window); + if (f->display.x->icon_desc == r.window) + refreshicon (f); else - dumprectangle (s, r.x, r.y, r.width, r.height); + dumprectangle (f, r.x, r.y, r.width, r.height); } XFlushQueue (); } -#endif +#endif /* HAVE_X11 */ -/* Process all expose events that are pending. - Redraws the cursor if necessary on any screen that - is not in the process of being updated with update_screen. */ +/* Process all expose events that are pending, for X10. + Redraws the cursor if necessary on any frame that + is not in the process of being updated with update_frame. */ +#ifndef HAVE_X11 static void x_do_pending_expose () { int mask; - struct screen *s; - Lisp_Object tail, screen; + struct frame *f; + Lisp_Object tail, frame; if (expose_all_windows) { expose_all_windows = 0; - for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr) + for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr) { register int temp_width, temp_height; int intborder; - screen = XCONS (tail)->car; - if (XTYPE (screen) != Lisp_Screen) + frame = XCONS (tail)->car; + if (XGCTYPE (frame) != Lisp_Frame) continue; - s = XSCREEN (screen); - if (! SCREEN_IS_X (s)) + f = XFRAME (frame); + if (! FRAME_X_P (f)) continue; - if (!s->visible) + if (!f->async_visible) continue; - if (!s->display.x->needs_exposure) + if (!f->display.x->needs_exposure) continue; - intborder = s->display.x->internal_border_width; + intborder = f->display.x->internal_border_width; - clear_cursor (s); - XGetWindowInfo (s->display.x->window_desc, &windowinfo); + clear_cursor (f); + XGetWindowInfo (FRAME_X_WINDOW (f), &windowinfo); temp_width = ((windowinfo.width - 2 * intborder - - s->display.x->v_scrollbar_width) - / FONT_WIDTH (s->display.x->font)); + - f->display.x->v_scroll_bar_width) + / FONT_WIDTH (f->display.x->font)); temp_height = ((windowinfo.height- 2 * intborder - - s->display.x->h_scrollbar_height) - / FONT_HEIGHT (s->display.x->font)); - if (temp_width != s->width || temp_height != s->height) + - f->display.x->h_scroll_bar_height) + / FONT_HEIGHT (f->display.x->font)); + if (temp_width != f->width || temp_height != f->height) { - change_screen_size (s, max (1, temp_height), - max (1, temp_width), 0); - x_resize_scrollbars (s); + change_frame_size (f, max (1, temp_height), + max (1, temp_width), 0, 1); + x_resize_scroll_bars (f); } - s->display.x->left_pos = windowinfo.x; - s->display.x->top_pos = windowinfo.y; - dumprectangle (s, 0, 0, PIXEL_WIDTH (s), PIXEL_HEIGHT (s)); + f->display.x->left_pos = windowinfo.x; + f->display.x->top_pos = windowinfo.y; + dumprectangle (f, 0, 0, PIXEL_WIDTH (f), PIXEL_HEIGHT (f)); #if 0 - dumpborder (s, 0); -#endif - s->display.x->needs_exposure = 0; - if (updating_screen != s) - x_display_cursor (s, 1); + dumpborder (f, 0); +#endif /* ! 0 */ + f->display.x->needs_exposure = 0; + if (updating_frame != f) + x_display_cursor (f, 1); XFlushQueue (); } } @@ -1136,338 +1269,382 @@ x_do_pending_expose () for various windows. */ #ifdef HAVE_X11 ; -#else +#else /* ! defined (HAVE_X11) */ dumpqueue (); -#endif +#endif /* ! defined (HAVE_X11) */ } +#endif #ifdef HAVE_X11 static void -screen_highlight (screen) - struct screen *screen; +frame_highlight (frame) + struct frame *frame; { - if (! EQ (Vx_no_window_manager, Qnil)) - XSetWindowBorder (x_current_display, screen->display.x->window_desc, - screen->display.x->border_pixel); - x_display_cursor (screen, 1); + /* We used to only do this if Vx_no_window_manager was non-nil, but + the ICCCM (section 4.1.6) says that the window's border pixmap + and border pixel are window attributes which are "private to the + client", so we can always change it to whatever we want. */ + BLOCK_INPUT; + XSetWindowBorder (x_current_display, FRAME_X_WINDOW (frame), + frame->display.x->border_pixel); + UNBLOCK_INPUT; + x_display_cursor (frame, 1); } static void -screen_unhighlight (screen) - struct screen *screen; +frame_unhighlight (frame) + struct frame *frame; { - if (! EQ (Vx_no_window_manager, Qnil)) - XSetWindowBorderPixmap (x_current_display, screen->display.x->window_desc, - screen->display.x->border_tile); - x_display_cursor (screen, 1); + /* We used to only do this if Vx_no_window_manager was non-nil, but + the ICCCM (section 4.1.6) says that the window's border pixmap + and border pixel are window attributes which are "private to the + client", so we can always change it to whatever we want. */ + BLOCK_INPUT; + XSetWindowBorderPixmap (x_current_display, FRAME_X_WINDOW (frame), + frame->display.x->border_tile); + UNBLOCK_INPUT; + x_display_cursor (frame, 1); } -#else /* X10 */ -/* Dump the border-emphasis of screen S. - If S is selected, this is a lining of the same color as the border, +#else /* ! defined (HAVE_X11) */ +/* Dump the border-emphasis of frame F. + If F is selected, this is a lining of the same color as the border, just within the border, occupying a portion of the internal border. - If S is not selected, it is background in the same place. + If F is not selected, it is background in the same place. If ALWAYS is 0, don't bother explicitly drawing if it's background. - ALWAYS = 1 is used when a screen becomes selected or deselected. + ALWAYS = 1 is used when a frame becomes selected or deselected. In that case, we also turn the cursor off and on again so it will appear in the proper shape (solid if selected; else hollow.) */ static void -dumpborder (s, always) - struct screen *s; +dumpborder (f, always) + struct frame *f; int always; { - int thickness = s->display.x->internal_border_width / 2; - int width = PIXEL_WIDTH (s); - int height = PIXEL_HEIGHT (s); + int thickness = f->display.x->internal_border_width / 2; + int width = PIXEL_WIDTH (f); + int height = PIXEL_HEIGHT (f); int pixel; - if (s != selected_screen) + if (f != selected_frame) { if (!always) return; - pixel = s->display.x->background_pixel; + pixel = f->display.x->background_pixel; } else { - pixel = s->display.x->border_pixel; + pixel = f->display.x->border_pixel; } - XPixSet (s->display.x->window_desc, 0, 0, width, thickness, pixel); - XPixSet (s->display.x->window_desc, 0, 0, thickness, height, pixel); - XPixSet (s->display.x->window_desc, 0, height - thickness, width, + XPixSet (FRAME_X_WINDOW (f), 0, 0, width, thickness, pixel); + XPixSet (FRAME_X_WINDOW (f), 0, 0, thickness, height, pixel); + XPixSet (FRAME_X_WINDOW (f), 0, height - thickness, width, thickness, pixel); - XPixSet (s->display.x->window_desc, width - thickness, 0, thickness, + XPixSet (FRAME_X_WINDOW (f), width - thickness, 0, thickness, height, pixel); if (always) - x_display_cursor (s, 1); + x_display_cursor (f, 1); } -#endif /* X10 */ +#endif /* ! defined (HAVE_X11) */ -static void XTscreen_rehighlight (); +static void XTframe_rehighlight (); -/* The focus has changed. Update the screens as necessary to reflect - the new situation. Note that we can't change the selected screen +/* The focus has changed. Update the frames as necessary to reflect + the new situation. Note that we can't change the selected frame here, because the lisp code we are interrupting might become confused. - Each event gets marked with the screen in which it occured, so the + Each event gets marked with the frame in which it occurred, so the lisp code can tell when the switch took place by examining the events. */ static void -x_new_focus_screen (screen) - struct screen *screen; +x_new_focus_frame (frame) + struct frame *frame; { - struct screen *old_focus = x_focus_screen; + struct frame *old_focus = x_focus_frame; int events_enqueued = 0; - if (screen != x_focus_screen) + if (frame != x_focus_frame) { /* Set this before calling other routines, so that they see - the correct value of x_focus_screen. */ - x_focus_screen = screen; + the correct value of x_focus_frame. */ + x_focus_frame = frame; if (old_focus && old_focus->auto_lower) - x_lower_screen (old_focus); + x_lower_frame (old_focus); #if 0 - selected_screen = screen; - XSET (XWINDOW (selected_screen->selected_window)->screen, - Lisp_Screen, selected_screen); - Fselect_window (selected_screen->selected_window); - choose_minibuf_screen (); -#endif - - if (x_focus_screen && x_focus_screen->auto_raise) - x_raise_screen (x_focus_screen); + selected_frame = frame; + XSET (XWINDOW (selected_frame->selected_window)->frame, + Lisp_Frame, selected_frame); + Fselect_window (selected_frame->selected_window); + choose_minibuf_frame (); +#endif /* ! 0 */ + + if (x_focus_frame && x_focus_frame->auto_raise) + x_raise_frame (x_focus_frame); } - XTscreen_rehighlight (); + XTframe_rehighlight (); } -/* The focus has changed, or we have make a screen's selected window - point to a window on a different screen (this happens with global - minibuffer screens). Shift the highlight as appropriate. */ +/* The focus has changed, or we have redirected a frame's focus to + another frame (this happens when a frame uses a surrogate + minibuffer frame). Shift the highlight as appropriate. */ static void -XTscreen_rehighlight () +XTframe_rehighlight () { - struct screen *old_highlight = x_highlight_screen; + struct frame *old_highlight = x_highlight_frame; - if (x_focus_screen) + if (x_focus_frame) { - x_highlight_screen = XSCREEN (SCREEN_FOCUS_SCREEN (x_focus_screen)); - if (x_highlight_screen->display.nothing == 0) - XSET (SCREEN_FOCUS_SCREEN (x_focus_screen), Lisp_Screen, - (x_highlight_screen = x_focus_screen)); + x_highlight_frame = + ((XGCTYPE (FRAME_FOCUS_FRAME (x_focus_frame)) == Lisp_Frame) + ? XFRAME (FRAME_FOCUS_FRAME (x_focus_frame)) + : x_focus_frame); + if (! FRAME_LIVE_P (x_highlight_frame)) + { + FRAME_FOCUS_FRAME (x_focus_frame) = Qnil; + x_highlight_frame = x_focus_frame; + } } else - x_highlight_screen = 0; + x_highlight_frame = 0; - if (x_highlight_screen != old_highlight) + if (x_highlight_frame != old_highlight) { if (old_highlight) - screen_unhighlight (old_highlight); - if (x_highlight_screen) - screen_highlight (x_highlight_screen); + frame_unhighlight (old_highlight); + if (x_highlight_frame) + frame_highlight (x_highlight_frame); } } -enum window_type -{ - no_window, - scrollbar_window, - text_window, -}; - -/* Position of the mouse in characters */ -unsigned int x_mouse_x, x_mouse_y; - -/* Offset in buffer of character under the pointer, or 0. */ -extern int mouse_buffer_offset; - -extern int buffer_posn_from_coords (); +/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */ -/* Symbols from xfns.c to denote the different parts of a window. */ -extern Lisp_Object Qmodeline_part, Qtext_part; - -#if 0 -/* Set *RESULT to an emacs input_event corresponding to MOTION_EVENT. - S is the screen in which the event occurred. - - WINDOW_TYPE says whether the event happened in a scrollbar window - or a text window, affecting the format of the event created. - - PART specifies which part of the scrollbar the event happened in, - if WINDOW_TYPE == scrollbar_window. - - If the mouse is over the same character as the last time we checked, - don't return an event; set result->kind to no_event. */ +/* Which modifier keys are on which modifier bits? + With each keystroke, X returns eight bits indicating which modifier + keys were held down when the key was pressed. The interpretation + of the top five modifier bits depends on what keys are attached + to them. If the Meta_L and Meta_R keysyms are on mod5, then mod5 + is the meta bit. + + x_meta_mod_mask is a mask containing the bits used for the meta key. + It may have more than one bit set, if more than one modifier bit + has meta keys on it. Basically, if EVENT is a KeyPress event, + the meta key is pressed if (EVENT.state & x_meta_mod_mask) != 0. + + x_shift_lock_mask is LockMask if the XK_Shift_Lock keysym is on the + lock modifier bit, or zero otherwise. Non-alphabetic keys should + only be affected by the lock modifier bit if XK_Shift_Lock is in + use; XK_Caps_Lock should only affect alphabetic keys. With this + arrangement, the lock modifier should shift the character if + (EVENT.state & x_shift_lock_mask) != 0. */ +static int x_meta_mod_mask, x_shift_lock_mask; + +/* These are like x_meta_mod_mask, but for different modifiers. */ +static int x_alt_mod_mask, x_super_mod_mask, x_hyper_mod_mask; + +/* Initialize mode_switch_bit and modifier_meaning. */ static void -notice_mouse_movement (result, motion_event, s, window_type, part) - struct input_event *result; - XMotionEvent motion_event; - struct screen *s; - int window_type; - Lisp_Object part; +x_find_modifier_meanings () { - int x, y, root_x, root_y, pix_x, pix_y; - unsigned int keys_and_buttons; - Window w, root_window; - - /* Unless we decide otherwise below, return a non-event. */ - result->kind = no_event; + int min_code, max_code; + KeySym *syms; + int syms_per_code; + XModifierKeymap *mods; + + x_meta_mod_mask = 0; + x_shift_lock_mask = 0; + x_alt_mod_mask = 0; + x_super_mod_mask = 0; + x_hyper_mod_mask = 0; - if (XQueryPointer (x_current_display, - s->display.x->window_desc, - &root_window, &w, - &root_x, &root_y, &pix_x, &pix_y, - &keys_and_buttons) - == False) - return; - -#if 0 - if (w == None) /* Mouse no longer in window. */ - return Qnil; +#ifdef HAVE_X11R4 + XDisplayKeycodes (x_current_display, &min_code, &max_code); +#else + min_code = x_current_display->min_keycode; + max_code = x_current_display->max_keycode; #endif - pixel_to_glyph_translation (s, pix_x, pix_y, &x, &y); - if (x == x_mouse_x && y == x_mouse_y) - return; + syms = XGetKeyboardMapping (x_current_display, + min_code, max_code - min_code + 1, + &syms_per_code); + mods = XGetModifierMapping (x_current_display); - x_mouse_x = x; - x_mouse_y = y; + /* Scan the modifier table to see which modifier bits the Meta and + Alt keysyms are on. */ + { + int row, col; /* The row and column in the modifier table. */ - /* What sort of window are we in now? */ - if (window_type == text_window) /* Text part */ - { - int modeline_p; + for (row = 3; row < 8; row++) + for (col = 0; col < mods->max_keypermod; col++) + { + KeyCode code = + mods->modifiermap[(row * mods->max_keypermod) + col]; - Vmouse_window = window_from_coordinates (s, x, y, &modeline_p); + /* Are any of this keycode's keysyms a meta key? */ + { + int code_col; - if (XTYPE (Vmouse_window) == Lisp_Window) - mouse_buffer_offset - = buffer_posn_from_coords (XWINDOW (Vmouse_window), x, y); - else - mouse_buffer_offset = 0; + for (code_col = 0; code_col < syms_per_code; code_col++) + { + int sym = syms[((code - min_code) * syms_per_code) + code_col]; - if (EQ (Vmouse_window, Qnil)) - Vmouse_screen_part = Qnil; - else if (modeline_p) - Vmouse_screen_part = Qmodeline_part; - else - Vmouse_screen_part = Qtext_part; - - result->kind = window_sys_event; - result->code = Qmouse_moved; + switch (sym) + { + case XK_Meta_L: + case XK_Meta_R: + x_meta_mod_mask |= (1 << row); + break; - return; - } - else if (window_type == scrollbar_window) /* Scrollbar */ - { - Vmouse_window = s->selected_window; - mouse_buffer_offset = 0; - Vmouse_screen_part = part; + case XK_Alt_L: + case XK_Alt_R: + x_alt_mod_mask |= (1 << row); + break; + + case XK_Hyper_L: + case XK_Hyper_R: + x_hyper_mod_mask |= (1 << row); + break; - result->kind = window_sys_event; - result->code = Qmouse_moved; + case XK_Super_L: + case XK_Super_R: + x_super_mod_mask |= (1 << row); + break; - return; + case XK_Shift_Lock: + /* Ignore this if it's not on the lock modifier. */ + if ((1 << row) == LockMask) + x_shift_lock_mask = LockMask; + break; + } + } + } + } + } + + /* If we couldn't find any meta keys, accept any alt keys as meta keys. */ + if (! x_meta_mod_mask) + { + x_meta_mod_mask = x_alt_mod_mask; + x_alt_mod_mask = 0; } - return; + /* If some keys are both alt and meta, + make them just meta, not alt. */ + if (x_alt_mod_mask & x_meta_mod_mask) + { + x_alt_mod_mask &= ~x_meta_mod_mask; + } + + XFree ((char *) syms); + XFreeModifiermap (mods); +} + + +/* Convert between the modifier bits X uses and the modifier bits + Emacs uses. */ +static unsigned int +x_x_to_emacs_modifiers (state) + unsigned int state; +{ + return ( ((state & (ShiftMask | x_shift_lock_mask)) ? shift_modifier : 0) + | ((state & ControlMask) ? ctrl_modifier : 0) + | ((state & x_meta_mod_mask) ? meta_modifier : 0) + | ((state & x_alt_mod_mask) ? alt_modifier : 0) + | ((state & x_super_mod_mask) ? super_modifier : 0) + | ((state & x_hyper_mod_mask) ? hyper_modifier : 0)); +} + +static unsigned int +x_emacs_to_x_modifiers (state) + unsigned int state; +{ + return ( ((state & alt_modifier) ? x_alt_mod_mask : 0) + | ((state & super_modifier) ? x_super_mod_mask : 0) + | ((state & hyper_modifier) ? x_hyper_mod_mask : 0) + | ((state & shift_modifier) ? ShiftMask : 0) + | ((state & ctrl_modifier) ? ControlMask : 0) + | ((state & meta_modifier) ? x_meta_mod_mask : 0)); } + +/* Return true iff KEYSYM is a vendor-specific keysym that we should + return as a function key. If you add a keysym to this, you should + make sure that the tables make_lispy_event uses contain a suitable + name for it. */ +static int +x_is_vendor_fkey (sym) + KeySym sym; +{ + return 0 +#ifdef DXK_Remove + || (sym == DXK_Remove) #endif + ; +} /* Mouse clicks and mouse movement. Rah. */ #ifdef HAVE_X11 -/* Given a pixel position (PIX_X, PIX_Y) on the screen S, return +/* Given a pixel position (PIX_X, PIX_Y) on the frame F, return glyph co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the glyph at X, Y occupies, if BOUNDS != 0. */ static void -pixel_to_glyph_coords (s, pix_x, pix_y, x, y, bounds) - SCREEN_PTR s; +pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds) + FRAME_PTR f; register unsigned int pix_x, pix_y; register int *x, *y; XRectangle *bounds; { - int ibw = s->display.x->internal_border_width; - int width, height; - FONT_TYPE *font = s->display.x->font; - - width = FONT_WIDTH (font); - height = FONT_HEIGHT (font); - - /* What line is it on? */ - if (pix_y < ibw) - *y = 0; - else if (pix_y > s->display.x->pixel_height - ibw) - *y = SCREEN_HEIGHT (s) - 1; - else - *y = (pix_y - ibw) / height; - - /* And what column? */ - if (pix_x < ibw) - *x = 0; - else if (pix_x > s->display.x->pixel_width - ibw) - *x = SCREEN_WIDTH (s) - 1; - else - *x = (pix_x - ibw) / width; + pix_x = PIXEL_TO_CHAR_COL (f, pix_x); + pix_y = PIXEL_TO_CHAR_ROW (f, pix_y); if (bounds) { - bounds->width = width; - bounds->height = height; - bounds->x = ibw + (*x * width); - bounds->y = ibw + (*y * height); + bounds->width = FONT_WIDTH (f->display.x->font); + bounds->height = FONT_HEIGHT (f->display.x->font); + bounds->x = CHAR_TO_PIXEL_COL (f, pix_x); + bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y); } -} -/* Any buttons grabbed. */ -unsigned int x_mouse_grabbed; + if (pix_x < 0) pix_x = 0; + else if (pix_x > f->width) pix_x = f->width; -/* Convert a set of X modifier bits to the proper form for a - struct input_event modifiers value. */ + if (pix_y < 0) pix_y = 0; + else if (pix_y > f->height) pix_y = f->height; -static Lisp_Object -x_convert_modifiers (state) - unsigned int state; -{ - return ( ((state & (ShiftMask | LockMask)) ? shift_modifier : 0) - | ((state & ControlMask) ? ctrl_modifier : 0) - | ((state & Mod1Mask) ? meta_modifier : 0)); + *x = pix_x; + *y = pix_y; } -extern struct screen *x_window_to_scrollbar (); -extern Lisp_Object Vmouse_event; +/* Any buttons grabbed. */ +unsigned int x_mouse_grabbed; /* 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 - the mouse. - - If PART and PREFIX are 0, then the event occurred in the text part; - otherwise it happened in a scrollbar. */ + the mouse. */ static Lisp_Object -construct_mouse_click (result, event, s, part, prefix) +construct_mouse_click (result, event, f) struct input_event *result; XButtonEvent *event; - struct screen *s; - int prefix; - Lisp_Object part; + struct frame *f; { - /* Initialize those fields text and scrollbar clicks hold in common. - 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 = no_event; - XSET (result->code, Lisp_Int, event->button); + result->kind = mouse_click; + XSET (result->code, Lisp_Int, event->button - Button1); result->timestamp = event->time; - result->modifiers = (x_convert_modifiers (event->state) - | (event->type == ButtonRelease ? up_modifier : 0)); + result->modifiers = (x_x_to_emacs_modifiers (event->state) + | (event->type == ButtonRelease + ? up_modifier + : down_modifier)); /* Notice if the mouse is still grabbed. */ if (event->type == ButtonPress) @@ -1483,33 +1660,14 @@ construct_mouse_click (result, event, s, part, prefix) Vmouse_depressed = Qnil; } - if (part) /* Scrollbar event */ - { - int pos, len; - - pos = event->y - (s->display.x->v_scrollbar_width - 2); - XSET (x_mouse_x, Lisp_Int, pos); - len = ((FONT_HEIGHT (s->display.x->font) * s->height) - + s->display.x->internal_border_width - - (2 * (s->display.x->v_scrollbar_width - 2))); - XSET (x_mouse_y, Lisp_Int, len); - - result->kind = scrollbar_click; - result->part = part; - XSET (result->x, Lisp_Int, (s->display.x->top_pos - event->y)); - XSET (result->y, Lisp_Int, s->display.x->pixel_height); - result->screen = s; - } - else /* Text Window Event */ - { - int row, column; + { + int row, column; - pixel_to_glyph_coords (s, event->x, event->y, &column, &row, NULL); - result->kind = mouse_click; - result->x = column; - result->y = row; - result->screen = s; - } + pixel_to_glyph_coords (f, event->x, event->y, &column, &row, NULL); + XFASTINT (result->x) = column; + XFASTINT (result->y) = row; + XSET (result->frame_or_window, Lisp_Frame, f); + } } @@ -1522,7 +1680,7 @@ construct_mouse_click (result, event, s, part, prefix) other kinds of events (focus changes and button clicks, for example), or by XQueryPointer calls; when one of these happens, we get another MotionNotify event the next time the mouse moves. This - is at least as efficient than getting motion events when mouse + is at least as efficient as getting motion events when mouse tracking is on, and I suspect only negligibly worse when tracking is off. @@ -1533,9 +1691,27 @@ construct_mouse_click (result, event, s, part, prefix) the server, which is very important. */ /* Where the mouse was last time we reported a mouse event. */ -static SCREEN_PTR last_mouse_screen; +static FRAME_PTR last_mouse_frame; static XRectangle last_mouse_glyph; +/* The scroll bar in which the last X motion event occurred. + + If the last X motion event occurred in a scroll bar, we set this + so XTmouse_position can know whether to report a scroll bar motion or + an ordinary motion. + + If the last X motion event didn't occur in a scroll bar, we set this + to Qnil, to tell XTmouse_position to return an ordinary motion event. */ +static Lisp_Object last_mouse_scroll_bar; + +/* This is a hack. We would really prefer that XTmouse_position would + return the time associated with the position it returns, but there + doesn't seem to be any way to wrest the timestamp from the server + along with the position query. So, we just keep track of the time + of the last movement we received, and return that in hopes that + it's somewhat accurate. */ +static Time last_mouse_movement_time; + /* Function to report a mouse movement to the mainstream Emacs code. The input handler calls this. @@ -1544,17 +1720,22 @@ static XRectangle last_mouse_glyph; 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_position (screen, event) - SCREEN_PTR screen; +note_mouse_movement (frame, event) + FRAME_PTR frame; XMotionEvent *event; { + last_mouse_movement_time = event->time; + /* Has the mouse moved off the glyph it was on at the last sighting? */ if (event->x < last_mouse_glyph.x || event->x >= last_mouse_glyph.x + last_mouse_glyph.width || event->y < last_mouse_glyph.y || event->y >= last_mouse_glyph.y + last_mouse_glyph.height) - mouse_moved = 1; + { + mouse_moved = 1; + last_mouse_scroll_bar = Qnil; + } else { /* It's on the same glyph. Call XQueryPointer so we'll get an @@ -1569,127 +1750,830 @@ note_mouse_position (screen, event) } } +static struct scroll_bar *x_window_to_scroll_bar (); +static void x_scroll_bar_report_motion (); + /* Return the current position of the mouse. + If the mouse movement started in a scroll bar, set *f, *bar_window, + and *part to the frame, window, and scroll bar part that the mouse + is over. Set *x and *y to the portion and whole of the mouse's + position on the scroll bar. + + If the mouse movement started elsewhere, set *f to the frame the + mouse is on, *bar_window to nil, and *x and *y to the character cell + the mouse is over. + + Set *time to the server timestamp for the time at which the mouse + was at this position. + + Don't store anything if we don't have a valid set of values to report. + This clears the mouse_moved flag, so we can wait for the next mouse - position. This also calls XQueryPointer, which will cause the - server to give us another MotionNotify when the mouse moves again. - */ + movement. This also calls XQueryPointer, which will cause the + server to give us another MotionNotify when the mouse moves + again. */ static void -XTmouse_position (s, x, y, time) - SCREEN_PTR *s; +XTmouse_position (f, bar_window, part, x, y, time) + FRAME_PTR *f; + Lisp_Object *bar_window; + enum scroll_bar_part *part; Lisp_Object *x, *y; - Lisp_Object *time; + unsigned long *time; { - int ix, iy, dummy; - Display *d = x_current_display; - Window guess, root, child; + FRAME_PTR f1; BLOCK_INPUT; - /* I would like to have an X function that just told me the - innermost window containing the mouse. - - /* There doesn't seem to be any way to just get the innermost window - containing the pointer, no matter what X screen it's on; you have - to guess a window, and then X will tell you which one of that - window's children it's in. If the pointer isn't in any of that - window's children, it gives you a root window that contains it. - - So we start with the selected screen's window and chase down - branches under the guidance of XQueryPointer until we hit a leaf - (all of the Emacs windows we care about are leaf windows). If at - any time XQueryPointer returns false, that means that the current - window does not contain the pointer any more (perhaps it moved), - so we start with the root window XQueryPointer has given us and - start again. */ - - guess = selected_screen->display.x->window_desc; - for (;;) - if (XQueryPointer (d, guess, &root, &child, - &dummy, &dummy, &ix, &iy, (unsigned int *) &dummy)) + if (! NILP (last_mouse_scroll_bar)) + x_scroll_bar_report_motion (f, bar_window, part, x, y, time); + else + { + Window root; + int root_x, root_y; + + Window dummy_window; + int dummy; + + mouse_moved = 0; + last_mouse_scroll_bar = Qnil; + + /* Figure out which root window we're on. */ + XQueryPointer (x_current_display, + DefaultRootWindow (x_current_display), + + /* The root window which contains the pointer. */ + &root, + + /* Trash which we can't trust if the pointer is on + a different screen. */ + &dummy_window, + + /* The position on that root window. */ + &root_x, &root_y, + + /* More trash we can't trust. */ + &dummy, &dummy, + + /* Modifier keys and pointer buttons, about which + we don't care. */ + (unsigned int *) &dummy); + + /* Now we have a position on the root; find the innermost window + containing the pointer. */ { - if (child == None) - /* Guess is a leaf window, and it contains the pointer. */ - break; - else - guess = child; + Window win, child; + int win_x, win_y; + int parent_x, parent_y; + + win = root; + for (;;) + { + XTranslateCoordinates (x_current_display, + + /* From-window, to-window. */ + root, win, + + /* From-position, to-position. */ + root_x, root_y, &win_x, &win_y, + + /* Child of win. */ + &child); + + if (child == None) + break; + + win = child; + parent_x = win_x; + parent_y = win_y; + } + + /* Now we know that: + win is the innermost window containing the pointer + (XTC says it has no child containing the pointer), + win_x and win_y are the pointer's position in it + (XTC did this the last time through), and + parent_x and parent_y are the pointer's position in win's parent. + (They are what win_x and win_y were when win was child. + If win is the root window, it has no parent, and + parent_{x,y} are invalid, but that's okay, because we'll + never use them in that case.) */ + + /* Is win one of our frames? */ + f1 = x_window_to_frame (win); + + /* If not, is it one of our scroll bars? */ + if (! f1) + { + struct scroll_bar *bar = x_window_to_scroll_bar (win); + + if (bar) + { + f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); + win_x = parent_x; + win_y = parent_y; + } + } + + if (f1) + { + /* Ok, we found a frame. Convert from pixels to characters + and store all the values. */ + + pixel_to_glyph_coords (f1, win_x, win_y, &win_x, &win_y, + &last_mouse_glyph); + + *bar_window = Qnil; + *part = 0; + *f = f1; + XSET (*x, Lisp_Int, win_x); + XSET (*y, Lisp_Int, win_y); + *time = last_mouse_movement_time; + } } - else - /* When XQueryPointer returns False, the pointer isn't in guess - anymore, but root is the root window of the screen we should - try instead. */ - guess = root; - - *s = last_mouse_screen = x_window_to_screen (guess); - if (! *s) - *x = *y = Qnil; + } + + UNBLOCK_INPUT; +} + +#else /* ! defined (HAVE_X11) */ +#define XEvent XKeyPressedEvent +#endif /* ! defined (HAVE_X11) */ + +/* Scroll bar support. */ + +/* Given an X window ID, find the struct scroll_bar which manages it. + This can be called in GC, so we have to make sure to strip off mark + bits. */ +static struct scroll_bar * +x_window_to_scroll_bar (window_id) + Window window_id; +{ + Lisp_Object tail, frame; + + for (tail = Vframe_list; + XGCTYPE (tail) == Lisp_Cons; + tail = XCONS (tail)->cdr) + { + Lisp_Object frame = XCONS (tail)->car; + Lisp_Object bar, condemned; + + /* All elements of Vframe_list should be frames. */ + if (XGCTYPE (frame) != Lisp_Frame) + abort (); + + /* Scan this frame's scroll bar list for a scroll bar with the + right window ID. */ + condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame)); + for (bar = FRAME_SCROLL_BARS (XFRAME (frame)); + /* This trick allows us to search both the ordinary and + condemned scroll bar lists with one loop. */ + ! GC_NILP (bar) || (bar = condemned, + condemned = Qnil, + ! GC_NILP (bar)); + bar = XSCROLL_BAR(bar)->next) + if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id) + return XSCROLL_BAR (bar); + } + + return 0; +} + +/* Open a new X window to serve as a scroll bar, and return the + scroll bar vector for it. */ +static struct scroll_bar * +x_scroll_bar_create (window, top, left, width, height) + struct window *window; + int top, left, width, height; +{ + FRAME_PTR frame = XFRAME (WINDOW_FRAME (window)); + struct scroll_bar *bar = + XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil)); + + BLOCK_INPUT; + + { + XSetWindowAttributes a; + unsigned long mask; + + a.background_pixel = frame->display.x->background_pixel; + a.event_mask = (ButtonPressMask | ButtonReleaseMask + | ButtonMotionMask | PointerMotionHintMask + | ExposureMask); + a.cursor = x_vertical_scroll_bar_cursor; + + mask = (CWBackPixel | CWEventMask | CWCursor); + + SET_SCROLL_BAR_X_WINDOW + (bar, + XCreateWindow (x_current_display, FRAME_X_WINDOW (frame), + + /* Position and size of scroll bar. */ + left, top, width, height, + + /* Border width, depth, class, and visual. */ + 0, CopyFromParent, CopyFromParent, CopyFromParent, + + /* Attributes. */ + mask, &a)); + } + + XSET (bar->window, Lisp_Window, window); + XSET (bar->top, Lisp_Int, top); + XSET (bar->left, Lisp_Int, left); + XSET (bar->width, Lisp_Int, width); + XSET (bar->height, Lisp_Int, height); + XSET (bar->start, Lisp_Int, 0); + XSET (bar->end, Lisp_Int, 0); + bar->dragging = Qnil; + + /* Add bar to its frame's list of scroll bars. */ + bar->next = FRAME_SCROLL_BARS (frame); + bar->prev = Qnil; + XSET (FRAME_SCROLL_BARS (frame), Lisp_Vector, bar); + if (! NILP (bar->next)) + XSET (XSCROLL_BAR (bar->next)->prev, Lisp_Vector, bar); + + XMapWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar)); + + UNBLOCK_INPUT; + + return bar; +} + +/* Draw BAR's handle in the proper position. + If the handle is already drawn from START to END, don't bother + redrawing it, unless REBUILD is non-zero; in that case, always + redraw it. (REBUILD is handy for drawing the handle after expose + events.) + + Normally, we want to constrain the start and end of the handle to + fit inside its rectangle, but if the user is dragging the scroll bar + handle, we want to let them drag it down all the way, so that the + bar's top is as far down as it goes; otherwise, there's no way to + move to the very end of the buffer. */ +static void +x_scroll_bar_set_handle (bar, start, end, rebuild) + struct scroll_bar *bar; + int start, end; + int rebuild; +{ + int dragging = ! NILP (bar->dragging); + Window w = SCROLL_BAR_X_WINDOW (bar); + GC gc = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))->display.x->normal_gc; + + /* If the display is already accurate, do nothing. */ + if (! rebuild + && start == XINT (bar->start) + && end == XINT (bar->end)) + return; + + BLOCK_INPUT; + + { + int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (XINT (bar->width)); + int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height)); + int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height)); + + /* Make sure the values are reasonable, and try to preserve + the distance between start and end. */ + { + int length = end - start; + + if (start < 0) + start = 0; + else if (start > top_range) + start = top_range; + end = start + length; + + if (end < start) + end = start; + else if (end > top_range && ! dragging) + end = top_range; + } + + /* Store the adjusted setting in the scroll bar. */ + XSET (bar->start, Lisp_Int, start); + XSET (bar->end, Lisp_Int, end); + + /* Clip the end position, just for display. */ + if (end > top_range) + end = top_range; + + /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels + below top positions, to make sure the handle is always at least + that many pixels tall. */ + end += VERTICAL_SCROLL_BAR_MIN_HANDLE; + + /* Draw the empty space above the handle. Note that we can't clear + zero-height areas; that means "clear to end of window." */ + if (0 < start) + XClearArea (x_current_display, w, + + /* x, y, width, height, and exposures. */ + VERTICAL_SCROLL_BAR_LEFT_BORDER, + VERTICAL_SCROLL_BAR_TOP_BORDER, + inside_width, start, + False); + + /* Draw the handle itself. */ + XFillRectangle (x_current_display, w, gc, + + /* x, y, width, height */ + VERTICAL_SCROLL_BAR_LEFT_BORDER, + VERTICAL_SCROLL_BAR_TOP_BORDER + start, + inside_width, end - start); + + + /* Draw the empty space below the handle. Note that we can't + clear zero-height areas; that means "clear to end of window." */ + if (end < inside_height) + XClearArea (x_current_display, w, + + /* x, y, width, height, and exposures. */ + VERTICAL_SCROLL_BAR_LEFT_BORDER, + VERTICAL_SCROLL_BAR_TOP_BORDER + end, + inside_width, inside_height - end, + False); + + } + + UNBLOCK_INPUT; +} + +/* Move a scroll bar around on the screen, to accommodate changing + window configurations. */ +static void +x_scroll_bar_move (bar, top, left, width, height) + struct scroll_bar *bar; + int top, left, width, height; +{ + BLOCK_INPUT; + + { + XWindowChanges wc; + unsigned int mask = 0; + + wc.x = left; + wc.y = top; + wc.width = width; + wc.height = height; + + if (left != XINT (bar->left)) mask |= CWX; + if (top != XINT (bar->top)) mask |= CWY; + if (width != XINT (bar->width)) mask |= CWWidth; + if (height != XINT (bar->height)) mask |= CWHeight; + + if (mask) + XConfigureWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar), + mask, &wc); + } + + XSET (bar->left, Lisp_Int, left); + XSET (bar->top, Lisp_Int, top); + XSET (bar->width, Lisp_Int, width); + XSET (bar->height, Lisp_Int, height); + + UNBLOCK_INPUT; +} + +/* Destroy the X window for BAR, and set its Emacs window's scroll bar + to nil. */ +static void +x_scroll_bar_remove (bar) + struct scroll_bar *bar; +{ + FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); + + BLOCK_INPUT; + + /* Destroy the window. */ + XDestroyWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar)); + + /* Disassociate this scroll bar from its window. */ + XWINDOW (bar->window)->vertical_scroll_bar = Qnil; + + UNBLOCK_INPUT; +} + +/* Set the handle of the vertical scroll bar for WINDOW to indicate + that we are displaying PORTION characters out of a total of WHOLE + characters, starting at POSITION. If WINDOW has no scroll bar, + create one. */ +static void +XTset_vertical_scroll_bar (window, portion, whole, position) + struct window *window; + int portion, whole, position; +{ + FRAME_PTR f = XFRAME (WINDOW_FRAME (window)); + int top = XINT (window->top); + int left = WINDOW_VERTICAL_SCROLL_BAR_COLUMN (window); + int height = WINDOW_VERTICAL_SCROLL_BAR_HEIGHT (window); + + /* Where should this scroll bar be, pixelwise? */ + int pixel_top = CHAR_TO_PIXEL_ROW (f, top); + int pixel_left = CHAR_TO_PIXEL_COL (f, left); + int pixel_width = VERTICAL_SCROLL_BAR_PIXEL_WIDTH (f); + int pixel_height = VERTICAL_SCROLL_BAR_PIXEL_HEIGHT (f, height); + + struct scroll_bar *bar; + + /* Does the scroll bar exist yet? */ + if (NILP (window->vertical_scroll_bar)) + bar = x_scroll_bar_create (window, + pixel_top, pixel_left, + pixel_width, pixel_height); else { - pixel_to_glyph_coords (*s, ix, iy, &ix, &iy, &last_mouse_glyph); - XSET (*x, Lisp_Int, ix); - XSET (*y, Lisp_Int, iy); + /* It may just need to be moved and resized. */ + bar = XSCROLL_BAR (window->vertical_scroll_bar); + x_scroll_bar_move (bar, pixel_top, pixel_left, pixel_width, pixel_height); + } + + /* Set the scroll bar's current state, unless we're currently being + dragged. */ + if (NILP (bar->dragging)) + { + int top_range = + VERTICAL_SCROLL_BAR_TOP_RANGE (pixel_height); + + if (whole == 0) + x_scroll_bar_set_handle (bar, 0, top_range, 0); + else + { + int start = ((double) position * top_range) / whole; + int end = ((double) (position + portion) * top_range) / whole; + + x_scroll_bar_set_handle (bar, start, end, 0); + } + } + + XSET (window->vertical_scroll_bar, Lisp_Vector, bar); +} + + +/* The following three hooks are used when we're doing a thorough + redisplay of the frame. We don't explicitly know which scroll bars + are going to be deleted, because keeping track of when windows go + away is a real pain - "Can you say set-window-configuration, boys + and girls?" Instead, we just assert at the beginning of redisplay + that *all* scroll bars are to be removed, and then save a scroll bar + from the fiery pit when we actually redisplay its window. */ + +/* Arrange for all scroll bars on FRAME to be removed at the next call + to `*judge_scroll_bars_hook'. A scroll bar may be spared if + `*redeem_scroll_bar_hook' is applied to its window before the judgement. */ +static void +XTcondemn_scroll_bars (frame) + FRAME_PTR frame; +{ + /* The condemned list should be empty at this point; if it's not, + then the rest of Emacs isn't using the condemn/redeem/judge + protocol correctly. */ + if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame))) + abort (); + + /* Move them all to the "condemned" list. */ + FRAME_CONDEMNED_SCROLL_BARS (frame) = FRAME_SCROLL_BARS (frame); + FRAME_SCROLL_BARS (frame) = Qnil; +} + +/* Unmark WINDOW's scroll bar for deletion in this judgement cycle. + Note that WINDOW isn't necessarily condemned at all. */ +static void +XTredeem_scroll_bar (window) + struct window *window; +{ + struct scroll_bar *bar; + + /* We can't redeem this window's scroll bar if it doesn't have one. */ + if (NILP (window->vertical_scroll_bar)) + abort (); + + bar = XSCROLL_BAR (window->vertical_scroll_bar); + + /* Unlink it from the condemned list. */ + { + FRAME_PTR f = XFRAME (WINDOW_FRAME (window)); + + if (NILP (bar->prev)) + { + /* If the prev pointer is nil, it must be the first in one of + the lists. */ + if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar)) + /* It's not condemned. Everything's fine. */ + return; + else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f), + window->vertical_scroll_bar)) + FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next; + else + /* If its prev pointer is nil, it must be at the front of + one or the other! */ + abort (); + } + else + XSCROLL_BAR (bar->prev)->next = bar->next; + + if (! NILP (bar->next)) + XSCROLL_BAR (bar->next)->prev = bar->prev; + + bar->next = FRAME_SCROLL_BARS (f); + bar->prev = Qnil; + XSET (FRAME_SCROLL_BARS (f), Lisp_Vector, bar); + if (! NILP (bar->next)) + XSET (XSCROLL_BAR (bar->next)->prev, Lisp_Vector, bar); + } +} + +/* Remove all scroll bars on FRAME that haven't been saved since the + last call to `*condemn_scroll_bars_hook'. */ +static void +XTjudge_scroll_bars (f) + FRAME_PTR f; +{ + Lisp_Object bar, next; + + bar = FRAME_CONDEMNED_SCROLL_BARS (f); + + /* Clear out the condemned list now so we won't try to process any + more events on the hapless scroll bars. */ + FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil; + + for (; ! NILP (bar); bar = next) + { + struct scroll_bar *b = XSCROLL_BAR (bar); + + x_scroll_bar_remove (b); + + next = b->next; + b->next = b->prev = Qnil; } - mouse_moved = 0; + /* Now there should be no references to the condemned scroll bars, + and they should get garbage-collected. */ +} - /* I don't know how to find the time for the last movement; it seems - like XQueryPointer ought to return it, but it doesn't. */ - *time = Qnil; + +/* Handle an Expose or GraphicsExpose event on a scroll bar. + + This may be called from a signal handler, so we have to ignore GC + mark bits. */ +static void +x_scroll_bar_expose (bar, event) + struct scroll_bar *bar; + XEvent *event; +{ + Window w = SCROLL_BAR_X_WINDOW (bar); + GC gc = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))->display.x->normal_gc; + + BLOCK_INPUT; + + x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1); + + /* Draw a one-pixel border just inside the edges of the scroll bar. */ + XDrawRectangle (x_current_display, w, gc, + + /* 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; } +/* 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. + + This may be called from a signal handler, so we have to ignore GC + mark bits. */ +static void +x_scroll_bar_handle_click (bar, event, emacs_event) + struct scroll_bar *bar; + XEvent *event; + struct input_event *emacs_event; +{ + if (XGCTYPE (bar->window) != Lisp_Window) + abort (); + + emacs_event->kind = scroll_bar_click; + XSET (emacs_event->code, Lisp_Int, event->xbutton.button - Button1); + emacs_event->modifiers = + (x_x_to_emacs_modifiers (event->xbutton.state) + | (event->type == ButtonRelease + ? up_modifier + : down_modifier)); + emacs_event->frame_or_window = bar->window; + emacs_event->timestamp = event->xbutton.time; + { + int internal_height = + VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height)); + int top_range = + VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height)); + int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER; + + if (y < 0) y = 0; + if (y > top_range) y = top_range; + + if (y < XINT (bar->start)) + emacs_event->part = scroll_bar_above_handle; + else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE) + emacs_event->part = scroll_bar_handle; + else + emacs_event->part = scroll_bar_below_handle; + + /* Just because the user has clicked on the handle doesn't mean + they want to drag it. Lisp code needs to be able to decide + whether or not we're dragging. */ +#if 0 + /* If the user has just clicked on the handle, record where they're + holding it. */ + if (event->type == ButtonPress + && emacs_event->part == scroll_bar_handle) + XSET (bar->dragging, Lisp_Int, y - XINT (bar->start)); +#endif + + /* If the user has released the handle, set it to its final position. */ + if (event->type == ButtonRelease + && ! NILP (bar->dragging)) + { + int new_start = y - XINT (bar->dragging); + int new_end = new_start + (XINT (bar->end) - XINT (bar->start)); + + x_scroll_bar_set_handle (bar, new_start, new_end, 0); + bar->dragging = Qnil; + } + + /* Same deal here as the other #if 0. */ +#if 0 + /* Clicks on the handle are always reported as occurring at the top of + the handle. */ + if (emacs_event->part == scroll_bar_handle) + emacs_event->x = bar->start; + else + XSET (emacs_event->x, Lisp_Int, y); +#else + XSET (emacs_event->x, Lisp_Int, y); +#endif + + XSET (emacs_event->y, Lisp_Int, top_range); + } +} + +/* Handle some mouse motion while someone is dragging the scroll bar. + + This may be called from a signal handler, so we have to ignore GC + mark bits. */ +static void +x_scroll_bar_note_movement (bar, event) + struct scroll_bar *bar; + XEvent *event; +{ + last_mouse_movement_time = event->xmotion.time; + + mouse_moved = 1; + XSET (last_mouse_scroll_bar, Lisp_Vector, bar); + + /* If we're dragging the bar, display it. */ + if (! GC_NILP (bar->dragging)) + { + /* Where should the handle be now? */ + int new_start = event->xmotion.y - XINT (bar->dragging); + + if (new_start != XINT (bar->start)) + { + int new_end = new_start + (XINT (bar->end) - XINT (bar->start)); + + x_scroll_bar_set_handle (bar, new_start, new_end, 0); + } + } + + /* Call XQueryPointer so we'll get an event the next time the mouse + moves and we can see *still* on the same position. */ + { + int dummy; + + XQueryPointer (event->xmotion.display, event->xmotion.window, + (Window *) &dummy, (Window *) &dummy, + &dummy, &dummy, &dummy, &dummy, + (unsigned int *) &dummy); + } +} + +/* Return information to the user about the current position of the mouse + on the scroll bar. */ +static void +x_scroll_bar_report_motion (f, bar_window, part, x, y, time) + FRAME_PTR *f; + Lisp_Object *bar_window; + enum scroll_bar_part *part; + Lisp_Object *x, *y; + unsigned long *time; +{ + struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar); + int win_x, win_y; + Window dummy_window; + int dummy_coord; + unsigned int dummy_mask; + + BLOCK_INPUT; + + /* Get the mouse's position relative to the scroll bar window, and + report that. */ + if (! XQueryPointer (x_current_display, + SCROLL_BAR_X_WINDOW (bar), + + /* Root, child, root x and root y. */ + &dummy_window, &dummy_window, + &dummy_coord, &dummy_coord, + + /* Position relative to scroll bar. */ + &win_x, &win_y, + + /* Mouse buttons and modifier keys. */ + &dummy_mask)) + *f = 0; + else + { + int inside_height + = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height)); + int top_range + = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height)); + + win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER; + + if (! NILP (bar->dragging)) + win_y -= XINT (bar->dragging); + + if (win_y < 0) + win_y = 0; + if (win_y > top_range) + win_y = top_range; + + *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window))); + *bar_window = bar->window; + + if (! NILP (bar->dragging)) + *part = scroll_bar_handle; + else if (win_y < XINT (bar->start)) + *part = scroll_bar_above_handle; + else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE) + *part = scroll_bar_handle; + else + *part = scroll_bar_below_handle; + + XSET (*x, Lisp_Int, win_y); + XSET (*y, Lisp_Int, top_range); + + mouse_moved = 0; + last_mouse_scroll_bar = Qnil; + } + + *time = last_mouse_movement_time; + + UNBLOCK_INPUT; +} + + +/* The screen has been cleared so we may have changed foreground or + background colors, and the scroll bars may need to be redrawn. + Clear out the scroll bars, and ask for expose events, so we can + redraw them. */ + +x_scroll_bar_clear (f) + FRAME_PTR f; +{ + Lisp_Object bar; + + for (bar = FRAME_SCROLL_BARS (f); + XTYPE (bar) == Lisp_Vector; + bar = XSCROLL_BAR (bar)->next) + XClearArea (x_current_display, SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)), + 0, 0, 0, 0, True); +} + + -static char *events[] = -{ - "0: ERROR!", - "1: REPLY", - "KeyPress", - "KeyRelease", - "ButtonPress", - "ButtonRelease", - "MotionNotify", - "EnterNotify", - "LeaveNotify", - "FocusIn", - "FocusOut", - "KeymapNotify", - "Expose", - "GraphicsExpose", - "NoExpose", - "VisibilityNotify", - "CreateNotify", - "DestroyNotify", - "UnmapNotify", - "MapNotify", - "MapRequest", - "ReparentNotify", - "ConfigureNotify", - "ConfigureRequest", - "GravityNotify", - "ResizeRequest", - "CirculateNotify", - "CirculateRequest", - "PropertyNotify", - "SelectionClear", - "SelectionRequest", - "SelectionNotify", - "ColormapNotify", - "ClientMessage", - "MappingNotify", - "LASTEvent" -}; -#else /* X10 */ -#define XEvent XKeyPressedEvent -#endif /* HAVE_X11 */ +/* The main X event-reading loop - XTread_socket. */ /* Timestamp 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; +/* This holds the state XLookupString needs to implement dead keys + and other tricks known as "compose processing". _X Window System_ + says that a portable program can't use this, but Stephen Gildea assures + 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_timestamp, above. */ +static XComposeStatus compose_status; + /* Communication with window managers. */ Atom Xatom_wm_protocols; @@ -1702,6 +2586,14 @@ Atom Xatom_wm_delete_window; Atom Xatom_wm_configure_denied; /* When our config request is denied */ Atom Xatom_wm_window_moved; /* When the WM moves us. */ +/* Window manager communication. */ +Atom Xatom_wm_change_state; + +/* Record the last 100 characters stored + to help debug the loss-of-chars-during-GC problem. */ +int temp_index; +short temp_buffer[100]; + /* Read events coming from the X server. This routine is called by the SIGIO handler. We return as soon as there are no more events to be read. @@ -1714,7 +2606,7 @@ Atom Xatom_wm_window_moved; /* When the WM moves us. */ WAITP is nonzero if we should block until input arrives. EXPECTED is nonzero if the caller knows input is available. */ -Lisp_Object +int XTread_socket (sd, bufp, numchars, waitp, expected) register int sd; register struct input_event *bufp; @@ -1727,18 +2619,18 @@ XTread_socket (sd, bufp, numchars, waitp, expected) int mask; int items_pending; /* How many items are in the X queue. */ XEvent event; - struct screen *s; - int event_found; + struct frame *f; + int event_found = 0; int prefix; Lisp_Object part; - if (x_input_blocked) + if (interrupt_input_blocked) { - x_pending_input = 1; + interrupt_input_pending = 1; return -1; } - x_pending_input = 0; + interrupt_input_pending = 0; BLOCK_INPUT; if (numchars <= 0) @@ -1750,7 +2642,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected) FIOSNBIO is ignored, and instead of signalling EWOULDBLOCK, a read returns 0, which Xlib interprets as equivalent to EPIPE. */ fcntl (fileno (stdin), F_SETFL, 0); -#endif +#endif /* ! defined (FIOSNBIO) */ #ifndef SIGIO #ifndef HAVE_SELECT @@ -1761,8 +2653,8 @@ XTread_socket (sd, bufp, numchars, waitp, expected) XPeekEvent (XDISPLAY &event); read_alarm_should_throw = 0; } -#endif -#endif +#endif /* HAVE_SELECT */ +#endif /* SIGIO */ while (XStuffPending () != 0) { @@ -1779,10 +2671,10 @@ XTread_socket (sd, bufp, numchars, waitp, expected) { if (event.xclient.data.l[0] == Xatom_wm_take_focus) { - s = x_window_to_screen (event.xclient.window); - if (s) - x_focus_on_screen (s); - /* Not certain about handling scrollbars here */ + f = x_window_to_frame (event.xclient.window); + if (f) + x_focus_on_frame (f); + /* Not certain about handling scroll bars here */ } else if (event.xclient.data.l[0] == Xatom_wm_save_yourself) { @@ -1797,9 +2689,9 @@ XTread_socket (sd, bufp, numchars, waitp, expected) } else if (event.xclient.data.l[0] == Xatom_wm_delete_window) { - struct screen *s = x_window_to_screen (event.xclient.window); + struct frame *f = x_window_to_frame (event.xclient.window); - if (s) + if (f) if (numchars > 0) { } @@ -1818,82 +2710,161 @@ XTread_socket (sd, bufp, numchars, waitp, expected) } break; +#ifdef NEW_SELECTIONS + case SelectionNotify: + x_handle_selection_notify (&event); + break; +#endif + case SelectionClear: /* Someone has grabbed ownership. */ +#ifdef NEW_SELECTIONS + { + XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event; + + if (numchars == 0) + abort (); + + bufp->kind = selection_clear_event; + SELECTION_EVENT_DISPLAY (bufp) = eventp->display; + SELECTION_EVENT_SELECTION (bufp) = eventp->selection; + SELECTION_EVENT_TIME (bufp) = eventp->time; + bufp++; + + count += 1; + numchars -= 1; + } +#else x_disown_selection (event.xselectionclear.window, event.xselectionclear.selection, event.xselectionclear.time); +#endif break; case SelectionRequest: /* Someone wants our selection. */ +#ifdef NEW_SELECTIONS + { + XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event; + + if (numchars == 0) + abort (); + + bufp->kind = selection_request_event; + SELECTION_EVENT_DISPLAY (bufp) = eventp->display; + SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor; + SELECTION_EVENT_SELECTION (bufp) = eventp->selection; + SELECTION_EVENT_TARGET (bufp) = eventp->target; + SELECTION_EVENT_PROPERTY (bufp) = eventp->property; + SELECTION_EVENT_TIME (bufp) = eventp->time; + bufp++; + + count += 1; + numchars -= 1; + } +#else x_answer_selection_request (event); +#endif break; case PropertyNotify: - /* If we were to do this synchronously, there'd be no worry - about re-selecting. */ - x_send_incremental (event); +#ifdef NEW_SELECTIONS + x_handle_property_notify (&event); +#else + /* If we're being told about a root window property, then it's + a cut buffer change. */ + if (event.xproperty.window == ROOT_WINDOW) + x_invalidate_cut_buffer_cache (&event.xproperty); + + /* Otherwise, we're probably handling an incremental + selection transmission. */ + else + { + /* If we were to do this synchronously, there'd be no worry + about re-selecting. */ + x_send_incremental (event); + } +#endif + break; + + case ReparentNotify: + f = x_window_to_frame (event.xreparent.window); + if (f) + f->display.x->parent_desc = event.xreparent.parent; break; case Expose: - s = x_window_to_screen (event.xexpose.window); - if (s) + f = x_window_to_frame (event.xexpose.window); + if (f) { - if (s->visible == 0) + if (f->async_visible == 0) { - s->visible = 1; - s->iconified = 0; - SET_SCREEN_GARBAGED (s); + f->async_visible = 1; + f->async_iconified = 0; + SET_FRAME_GARBAGED (f); } else - dumprectangle (x_window_to_screen (event.xexpose.window), - event.xexpose.x, event.xexpose.y, - event.xexpose.width, event.xexpose.height); + { + dumprectangle (x_window_to_frame (event.xexpose.window), + event.xexpose.x, event.xexpose.y, + event.xexpose.width, event.xexpose.height); + } + } + else + { + struct scroll_bar *bar + = x_window_to_scroll_bar (event.xexpose.window); + + if (bar) + x_scroll_bar_expose (bar, &event); } break; case GraphicsExpose: /* This occurs when an XCopyArea's source area was obscured or not available.*/ - dumprectangle (x_window_to_screen (event.xgraphicsexpose.drawable), - event.xgraphicsexpose.x, event.xgraphicsexpose.y, - event.xgraphicsexpose.width, - event.xgraphicsexpose.height); + f = x_window_to_frame (event.xgraphicsexpose.drawable); + if (f) + { + dumprectangle (f, + event.xgraphicsexpose.x, event.xgraphicsexpose.y, + event.xgraphicsexpose.width, + event.xgraphicsexpose.height); + } break; case NoExpose: /* This occurs when an XCopyArea's source area was completely available */ break; -#else /* not HAVE_X11 */ +#else /* ! defined (HAVE_X11) */ case ExposeWindow: if (event.subwindow != 0) break; /* duplicate event */ - s = x_window_to_screen (event.window); - if (event.window == s->display.x->icon_desc) + f = x_window_to_frame (event.window); + if (event.window == f->display.x->icon_desc) { - refreshicon (s); - s->iconified = 1; + refreshicon (f); + f->async_iconified = 1; } - if (event.window == s->display.x->window_desc) + if (event.window == FRAME_X_WINDOW (f)) { /* Say must check all windows' needs_exposure flags. */ expose_all_windows = 1; - s->display.x->needs_exposure = 1; - s->visible = 1; + f->display.x->needs_exposure = 1; + f->async_visible = 1; } break; case ExposeRegion: if (event.subwindow != 0) break; /* duplicate event */ - s = x_window_to_screen (event.window); - if (event.window == s->display.x->icon_desc) + f = x_window_to_frame (event.window); + if (event.window == f->display.x->icon_desc) { - refreshicon (s); + refreshicon (f); break; } /* If window already needs full redraw, ignore this rectangle. */ - if (expose_all_windows && s->display.x->needs_exposure) + if (expose_all_windows && f->display.x->needs_exposure) break; /* Put the event on the queue of rectangles to redraw. */ if (enqueue_event (&event, &x_expose_queue)) @@ -1902,7 +2873,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected) { /* Say must check all windows' needs_exposure flags. */ expose_all_windows = 1; - s->display.x->needs_exposure = 1; + f->display.x->needs_exposure = 1; } break; @@ -1910,36 +2881,37 @@ XTread_socket (sd, bufp, numchars, waitp, expected) /* This should happen only when we are expecting it, in x_read_exposes. */ abort (); -#endif /* not HAVE_X11 */ +#endif /* ! defined (HAVE_X11) */ #ifdef HAVE_X11 case UnmapNotify: - { - XWMHints *hints; - - s = x_window_to_screen (event.xunmap.window); - if (s) /* S may no longer exist if - the screen was deleted. */ - { - /* While a screen is unmapped, display generation is - disabled; you don't want to spend time updating a - display that won't ever be seen. */ - s->visible = 0; - x_mouse_x = x_mouse_y = -1; - } - } + f = x_window_to_frame (event.xunmap.window); + if (f) /* F may no longer exist if + the frame was deleted. */ + { + /* While a frame is unmapped, display generation is + disabled; you don't want to spend time updating a + display that won't ever be seen. */ + f->async_visible = 0; + /* The window manager never makes a window invisible + ("withdrawn"); all it does is switch between visible + and iconified. Frames get into the invisible state + only through x_make_frame_invisible. */ + if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f)) + f->async_iconified = 1; + } break; case MapNotify: - s = x_window_to_screen (event.xmap.window); - if (s) + f = x_window_to_frame (event.xmap.window); + if (f) { - s->visible = 1; - s->iconified = 0; + f->async_visible = 1; + f->async_iconified = 0; /* wait_reading_process_input will notice this and update - the screen's display structures. */ - SET_SCREEN_GARBAGED (s); + the frame's display structures. */ + SET_FRAME_GARBAGED (f); } break; @@ -1947,56 +2919,80 @@ XTread_socket (sd, bufp, numchars, waitp, expected) case VisibilityNotify: break; -#else +#else /* ! defined (HAVE_X11) */ case UnmapWindow: - s = x_window_to_screen (event.window); - if (event.window == s->display.x->icon_desc) - s->iconified = 0; - if (event.window == s->display.x->window_desc) - s->visible = 0; + f = x_window_to_frame (event.window); + if (event.window == f->display.x->icon_desc) + f->async_iconified = 0; + if (event.window == FRAME_X_WINDOW (f)) + f->async_visible = 0; break; -#endif /* HAVE_X11 */ +#endif /* ! defined (HAVE_X11) */ #ifdef HAVE_X11 case KeyPress: - s = x_window_to_screen (event.xkey.window); - if (s != 0) + f = x_window_to_frame (event.xkey.window); + + if (f != 0) { - KeySym keysym; - XComposeStatus status; - char copy_buffer[80]; - int modifiers = event.xkey.state; - - /* Some keyboards generate different characters - depending on the state of the meta key, in an attempt - to support non-English typists. It would be nice to - keep this functionality somehow, but for now, we will - just clear the meta-key flag to get the 'pure' character. */ - event.xkey.state &= ~Mod1Mask; - - /* This will have to go some day... */ - nbytes = XLookupString (&event.xkey, - copy_buffer, - 80, - &keysym, - &status); + KeySym keysym, orig_keysym; + unsigned char copy_buffer[80]; + int modifiers; + + event.xkey.state + |= x_emacs_to_x_modifiers (extra_keyboard_modifiers); + modifiers = event.xkey.state; + + /* This will have to go some day... */ + + /* make_lispy_event turns chars into control chars. + Don't do it here because XLookupString is too eager. */ + event.xkey.state &= ~ControlMask; + nbytes = + XLookupString (&event.xkey, copy_buffer, 80, &keysym, + &compose_status); /* Strip off the vendor-specific keysym bit, and take a shot at recognizing the codes. HP servers have extra keysyms that fit into the MiscFunctionKey category. */ + orig_keysym = keysym; keysym &= ~(1<<28); if (numchars > 1) { - if (IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */ - || IsMiscFunctionKey (keysym) /* 0xff60 <= x < 0xff80 */ - || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */ - || IsFunctionKey (keysym)) /* 0xffbe <= x < 0xffe1 */ + if (((keysym >= XK_BackSpace && keysym <= XK_Escape) + || keysym == XK_Delete + || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */ + || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */ +#ifdef HPUX + /* This recognizes the "extended function keys". + It seems there's no cleaner way. + Test IsModifierKey to avoid handling mode_switch + incorrectly. */ + || ((unsigned) (keysym) >= XK_Select + && (unsigned)(keysym) < XK_KP_Space) +#endif + || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */ + || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */ + || x_is_vendor_fkey (orig_keysym)) + && ! (IsModifierKey (orig_keysym) +#ifndef HAVE_X11R5 +#ifdef XK_Mode_switch + || ((unsigned)(orig_keysym) == XK_Mode_switch) +#endif +#ifdef XK_Num_Lock + || ((unsigned)(orig_keysym) == XK_Num_Lock) +#endif +#endif /* not HAVE_X11R5 */ + )) { + if (temp_index == sizeof temp_buffer / sizeof (short)) + temp_index = 0; + temp_buffer[temp_index++] = keysym; bufp->kind = non_ascii_keystroke; - XSET (bufp->code, Lisp_Int, (unsigned) keysym - 0xff50); - bufp->screen = XSCREEN (SCREEN_FOCUS_SCREEN (s)); - bufp->modifiers = x_convert_modifiers (modifiers); + XSET (bufp->code, Lisp_Int, (unsigned) keysym - 0xff00); + XSET (bufp->frame_or_window, Lisp_Frame, f); + bufp->modifiers = x_x_to_emacs_modifiers (modifiers); bufp->timestamp = event.xkey.time; bufp++; count++; @@ -2006,40 +3002,37 @@ XTread_socket (sd, bufp, numchars, waitp, expected) { register int i; - if (nbytes == 1) + for (i = 0; i < nbytes; i++) { - if (modifiers & Mod1Mask) - *copy_buffer |= METABIT; + if (temp_index == sizeof temp_buffer / sizeof (short)) + temp_index = 0; + temp_buffer[temp_index++] = copy_buffer[i]; bufp->kind = ascii_keystroke; - XSET (bufp->code, Lisp_Int, *copy_buffer); - bufp->screen = XSCREEN (SCREEN_FOCUS_SCREEN (s)); + XSET (bufp->code, Lisp_Int, copy_buffer[i]); + XSET (bufp->frame_or_window, Lisp_Frame, f); + bufp->modifiers = x_x_to_emacs_modifiers (modifiers); bufp->timestamp = event.xkey.time; bufp++; } - else - for (i = nbytes - 1; i > 1; i--) - { - bufp->kind = ascii_keystroke; - XSET (bufp->code, Lisp_Int, copy_buffer[i]); - bufp->screen = XSCREEN (SCREEN_FOCUS_SCREEN (s)); - bufp->timestamp = event.xkey.time; - bufp++; - } count += nbytes; numchars -= nbytes; } + else + abort (); } + else + abort (); } break; -#else +#else /* ! defined (HAVE_X11) */ case KeyPressed: { register char *where_mapping; - s = x_window_to_screen (event.window); + f = x_window_to_frame (event.window); /* Ignore keys typed on icon windows. */ - if (s != 0 && event.window == s->display.x->icon_desc) + if (f != 0 && event.window == f->display.x->icon_desc) break; where_mapping = XLookupMapping (&event, &nbytes); /* Nasty fix for arrow keys */ @@ -2071,7 +3064,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected) bufp->kind = ascii_keystroke; XSET (bufp->code, Lisp_Int, where_mapping[i]); XSET (bufp->time, Lisp_Int, event.xkey.time); - bufp->screen = XSCREEN (SCREEN_FOCUS_SCREEN (s)); + XSET (bufp->frame_or_window, Lisp_Frame, f); bufp++; } count += nbytes; @@ -2079,85 +3072,73 @@ XTread_socket (sd, bufp, numchars, waitp, expected) } } break; -#endif /* HAVE_X11 */ +#endif /* ! defined (HAVE_X11) */ #ifdef HAVE_X11 + + /* 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: - s = x_window_to_screen (event.xcrossing.window); + f = x_window_to_frame (event.xcrossing.window); - if (event.xcrossing.detail == NotifyInferior) /* Left Scrollbar */ - ; - else if (event.xcrossing.focus) /* Entered Window */ + if (event.xcrossing.focus) /* Entered Window */ { - /* If we decide we want to generate an event to be seen - by the rest of Emacs, we put it here. */ - struct input_event emacs_event; - emacs_event.kind = no_event; - /* Avoid nasty pop/raise loops. */ - if (s && (!(s->auto_raise) - || !(s->auto_lower) + if (f && (!(f->auto_raise) + || !(f->auto_lower) || (event.xcrossing.time - enter_timestamp) > 500)) { - x_new_focus_screen (s); + x_new_focus_frame (f); enter_timestamp = event.xcrossing.time; } -#if 0 - else if ((s = x_window_to_scrollbar (event.xcrossing.window, - &part, &prefix))) - /* Fake a motion event */ - notice_mouse_movement (&emacs_event, - event.xmotion, s, scrollbar_window, - part); -#endif - -#if 0 - if (! EQ (Vx_send_mouse_movement_events, Qnil) - && numchars >= 1 - && emacs_event.kind != no_event) - { - bcopy (&emacs_event, bufp, sizeof (struct input_event)); - bufp++; - count++; - numchars--; - } -#endif } - else if (s == x_focus_screen) - x_new_focus_screen (0); -#if 0 - else if (s = x_window_to_screen (event.xcrossing.window)) - x_mouse_screen = s; -#endif + else if (f == x_focus_frame) + x_new_focus_frame (0); break; case FocusIn: - s = x_window_to_screen (event.xfocus.window); - if (s) - x_new_focus_screen (s); + f = x_window_to_frame (event.xfocus.window); + if (event.xfocus.detail != NotifyPointer) + x_focus_event_frame = f; + if (f) + x_new_focus_frame (f); break; + case LeaveNotify: - if (event.xcrossing.detail != NotifyInferior - && event.xcrossing.subwindow == None - && event.xcrossing.mode == NotifyNormal) + f = x_window_to_frame (event.xcrossing.window); + + if (event.xcrossing.focus) + { + if (! x_focus_event_frame) + x_new_focus_frame (0); + else + x_new_focus_frame (f); + } + else { - s = x_window_to_screen (event.xcrossing.window); - if (event.xcrossing.focus) - x_new_focus_screen (s); - else if (s == x_focus_screen) - x_new_focus_screen (0); + if (f == x_focus_event_frame) + x_focus_event_frame = 0; + if (f == x_focus_frame) + x_new_focus_frame (0); } break; case FocusOut: - s = x_window_to_screen (event.xfocus.window); - if (s && s == x_focus_screen) - x_new_focus_screen (0); + f = x_window_to_frame (event.xfocus.window); + if (event.xfocus.detail != NotifyPointer + && f == x_focus_event_frame) + x_focus_event_frame = 0; + if (f && f == x_focus_frame) + x_new_focus_frame (0); break; -#else /* not HAVE_X11 */ +#else /* ! defined (HAVE_X11) */ case EnterWindow: if ((event.detail & 0xFF) == 1) @@ -2166,12 +3147,10 @@ XTread_socket (sd, bufp, numchars, waitp, expected) break; /* Entering our own subwindow. */ { - struct screen *old_s = x_input_screen; + f = x_window_to_frame (event.window); + x_mouse_frame = f; - s = x_window_to_screen (event.window); - x_mouse_screen = s; - - x_new_focus_screen (s); + x_new_focus_frame (f); } break; @@ -2181,71 +3160,89 @@ XTread_socket (sd, bufp, numchars, waitp, expected) if (event.subwindow != 0) break; /* Leaving our own subwindow. */ - x_mouse_screen = 0; - if (x_focus_screen == 0 - && x_input_screen != 0 - && x_input_screen == x_window_to_screen (event.window) - && event.window == x_input_screen->display.x->window_desc) + x_mouse_frame = 0; + if (x_focus_frame == 0 + && x_input_frame != 0 + && x_input_frame == x_window_to_frame (event.window) + && event.window == FRAME_X_WINDOW (x_input_frame)) { - s = x_input_screen; - x_input_screen = 0; - if (s) - screen_unhighlight (s); + f = x_input_frame; + x_input_frame = 0; + if (f) + frame_unhighlight (f); } break; -#endif /* not HAVE_X11 */ +#endif /* ! defined (HAVE_X11) */ #ifdef HAVE_X11 case MotionNotify: { - s = x_window_to_screen (event.xmotion.window); - if (s) - note_mouse_position (s, &event.xmotion); -#if 0 - else if ((s = x_window_to_scrollbar (event.xmotion.window, - &part, &prefix))) + f = x_window_to_frame (event.xmotion.window); + if (f) + note_mouse_movement (f, &event.xmotion); + else { - What should go here? + struct scroll_bar *bar = + x_window_to_scroll_bar (event.xmotion.window); + + if (bar) + x_scroll_bar_note_movement (bar, &event); } -#endif } break; case ConfigureNotify: - { - int rows, columns; - s = x_window_to_screen (event.xconfigure.window); - if (!s) - break; + f = x_window_to_frame (event.xconfigure.window); + if (f) + { + int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height); + int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width); + + /* Even if the number of character rows and columns has + not changed, the font size may have changed, so we need + to check the pixel dimensions as well. */ + if (columns != f->width + || rows != f->height + || event.xconfigure.width != f->display.x->pixel_width + || event.xconfigure.height != f->display.x->pixel_height) + { + change_frame_size (f, rows, columns, 0, 1); + SET_FRAME_GARBAGED (f); + } - columns = ((event.xconfigure.width - - (2 * s->display.x->internal_border_width) - - s->display.x->v_scrollbar_width) - / FONT_WIDTH (s->display.x->font)); - rows = ((event.xconfigure.height - - (2 * s->display.x->internal_border_width) - - s->display.x->h_scrollbar_height) - / FONT_HEIGHT (s->display.x->font)); - - /* Even if the number of character rows and columns has - not changed, the font size may have changed, so we need - to check the pixel dimensions as well. */ - if (columns != s->width - || rows != s->height - || event.xconfigure.width != s->display.x->pixel_width - || event.xconfigure.height != s->display.x->pixel_height) - { - change_screen_size (s, rows, columns, 0); - x_resize_scrollbars (s); - SET_SCREEN_GARBAGED (s); - } + if (! event.xconfigure.send_event) + { + 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. */ + f->display.x->window_desc, + 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; + } - s->display.x->pixel_width = event.xconfigure.width; - s->display.x->pixel_height = event.xconfigure.height; - s->display.x->left_pos = event.xconfigure.x; - s->display.x->top_pos = event.xconfigure.y; - break; - } + 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; + } + break; case ButtonPress: case ButtonRelease: @@ -2255,23 +3252,21 @@ XTread_socket (sd, bufp, numchars, waitp, expected) struct input_event emacs_event; emacs_event.kind = no_event; - s = x_window_to_screen (event.xbutton.window); - if (s) - if (!x_focus_screen || (s == x_focus_screen)) - construct_mouse_click (&emacs_event, - &event, s, 0, 0); - else - continue; + f = x_window_to_frame (event.xbutton.window); + if (f) + { + if (!x_focus_frame || (f == x_focus_frame)) + construct_mouse_click (&emacs_event, + &event, f); + } else - if ((s = x_window_to_scrollbar (event.xbutton.window, - &part, &prefix))) - { - if (!x_focus_screen || (selected_screen == x_focus_screen)) - construct_mouse_click (&emacs_event, - &event, s, part, prefix); - else - continue; - } + { + struct scroll_bar *bar = + x_window_to_scroll_bar (event.xbutton.window); + + if (bar) + x_scroll_bar_handle_click (bar, &event, &emacs_event); + } if (numchars >= 1 && emacs_event.kind != no_event) { @@ -2283,24 +3278,24 @@ XTread_socket (sd, bufp, numchars, waitp, expected) } break; -#else /* not HAVE_X11 */ +#else /* ! defined (HAVE_X11) */ case ButtonPressed: case ButtonReleased: - s = x_window_to_screen (event.window); - if (s) + f = x_window_to_frame (event.window); + if (f) { - if (event.window == s->display.x->icon_desc) + if (event.window == f->display.x->icon_desc) { - x_make_screen_visible (s); + x_make_frame_visible (f); if (warp_mouse_on_deiconify) - XWarpMouse (s->display.x->window_desc, 10, 10); + XWarpMouse (FRAME_X_WINDOW (f), 10, 10); break; } - if (event.window == s->display.x->window_desc) + if (event.window == FRAME_X_WINDOW (f)) { - if (s->auto_raise) - x_raise_screen (s); + if (f->auto_raise) + x_raise_frame (f); } } enqueue_event (&event, &x_mouse_queue); @@ -2308,13 +3303,13 @@ XTread_socket (sd, bufp, numchars, waitp, expected) { bufp->kind = ascii_keystroke; bufp->code = (char) 'X' & 037; /* C-x */ - bufp->screen = XSCREEN (SCREEN_FOCUS_SCREEN (s)); + XSET (bufp->frame_or_window, Lisp_Frame, f); XSET (bufp->time, Lisp_Int, event.xkey.time); bufp++; bufp->kind = ascii_keystroke; bufp->code = (char) 0; /* C-@ */ - bufp->screen = XSCREEN (SCREEN_FOCUS_SCREEN (s)); + XSET (bufp->frame_or_window, Lisp_Frame, f); XSET (bufp->time, Lisp_Int, event.xkey.time); bufp++; @@ -2322,7 +3317,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected) numchars -= 2; } break; -#endif /* not HAVE_X11 */ +#endif /* ! defined (HAVE_X11) */ #ifdef HAVE_X11 @@ -2331,13 +3326,19 @@ XTread_socket (sd, bufp, numchars, waitp, expected) case CirculateRequest: break; -#endif /* HAVE_X11 */ +#endif /* ! defined (HAVE_X11) */ case MappingNotify: - if (event.xmapping.request == MappingKeyboard) - /* Someone has changed the keyboard mapping - flush the - local cache. */ - XRefreshKeyboardMapping (&event.xmapping); + /* Someone has changed the keyboard mapping - update the + local cache. */ + switch (event.xmapping.request) + { + case MappingModifier: + x_find_modifier_meanings (); + /* This is meant to fall through. */ + case MappingKeyboard: + XRefreshKeyboardMapping (&event.xmapping); + } break; default: @@ -2345,27 +3346,28 @@ XTread_socket (sd, bufp, numchars, waitp, expected) } } -#if 0 #ifdef HAVE_SELECT if (expected && ! event_found) { /* AOJ 880406: if select returns true but XPending doesn't, it means that there is an EOF condition; in other words, that X has died. Act as if there had been a hangup. */ - int fd = ConnectionNumber (x_current_display); - int mask = 1 << fd; + SELECT_TYPE mask; + EMACS_TIME timeout; - if (0 != select (fd + 1, &mask, (long *) 0, (long *) 0, - (EMACS_TIME) 0) + FD_SET(fd, &mask); + EMACS_SET_SECS_USECS (timeout, 0, 0); + if (0 != select (fd + 1, &mask, (long *) 0, (long *) 0, &timeout) && !XStuffPending ()) kill (getpid (), SIGHUP); } -#endif /* HAVE_SELECT */ -#endif +#endif /* ! defined (HAVE_SELECT) */ - if (updating_screen == 0) +#ifndef HAVE_X11 + if (updating_frame == 0) x_do_pending_expose (); +#endif UNBLOCK_INPUT; return count; @@ -2380,7 +3382,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected) static void x_read_exposes () { - struct screen *s; + struct frame *f; XKeyPressedEvent event; while (1) @@ -2392,16 +3394,16 @@ x_read_exposes () case ExposeWindow: if (event.subwindow != 0) break; /* duplicate event */ - s = x_window_to_screen (event.window); - if (event.window == s->display.x->icon_desc) + f = x_window_to_frame (event.window); + if (event.window == f->display.x->icon_desc) { - refreshicon (s); + refreshicon (f); break; } - if (event.window == s->display.x->window_desc) + if (event.window == FRAME_X_WINDOW (f)) { expose_all_windows = 1; - s->display.x->needs_exposure = 1; + f->display.x->needs_exposure = 1; break; } break; @@ -2409,14 +3411,14 @@ x_read_exposes () case ExposeRegion: if (event.subwindow != 0) break; /* duplicate event */ - s = x_window_to_screen (event.window); - if (event.window == s->display.x->icon_desc) + f = x_window_to_frame (event.window); + if (event.window == f->display.x->icon_desc) { - refreshicon (s); + refreshicon (f); break; } /* If window already needs full redraw, ignore this rectangle. */ - if (expose_all_windows && s->display.x->needs_exposure) + if (expose_all_windows && f->display.x->needs_exposure) break; /* Put the event on the queue of rectangles to redraw. */ if (enqueue_event (&event, &x_expose_queue)) @@ -2425,7 +3427,7 @@ x_read_exposes () { /* Say must check all windows' needs_exposure flags. */ expose_all_windows = 1; - s->display.x->needs_exposure = 1; + f->display.x->needs_exposure = 1; } break; @@ -2437,334 +3439,340 @@ x_read_exposes () #endif /* HAVE_X11 */ +/* Drawing the cursor. */ + + /* Draw a hollow box cursor. Don't change the inside of the box. */ static void -x_draw_box (s) - struct screen *s; +x_draw_box (f) + struct frame *f; { - int left = s->cursor_x * FONT_WIDTH (s->display.x->font) - + s->display.x->internal_border_width; - int top = s->cursor_y * FONT_HEIGHT (s->display.x->font) - + s->display.x->internal_border_width; - int width = FONT_WIDTH (s->display.x->font); - int height = FONT_HEIGHT (s->display.x->font); + 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); #ifdef HAVE_X11 - /* Perhaps we should subtract 1 from width and height... */ - XDrawRectangle (x_current_display, s->display.x->window_desc, - s->display.x->cursor_gc, + XDrawRectangle (x_current_display, FRAME_X_WINDOW (f), + f->display.x->cursor_gc, left, top, width - 1, height - 1); -#else - XPixSet (s->display.x->window_desc, +#else /* ! defined (HAVE_X11) */ + XPixSet (FRAME_X_WINDOW (f), left, top, width, 1, - s->display.x->cursor_pixel); + f->display.x->cursor_pixel); - XPixSet (s->display.x->window_desc, + XPixSet (FRAME_X_WINDOW (f), left, top, 1, height, - s->display.x->cursor_pixel); + f->display.x->cursor_pixel); - XPixSet (s->display.x->window_desc, + XPixSet (FRAME_X_WINDOW (f), left+width-1, top, 1, height, - s->display.x->cursor_pixel); + f->display.x->cursor_pixel); - XPixSet (s->display.x->window_desc, + XPixSet (FRAME_X_WINDOW (f), left, top+height-1, width, 1, - s->display.x->cursor_pixel); -#endif /* HAVE_X11 */ + f->display.x->cursor_pixel); +#endif /* ! defined (HAVE_X11) */ } -/* Clear the cursor of screen S to background color, +/* Clear the cursor of frame F to background color, and mark the cursor as not shown. This is used when the text where the cursor is is about to be rewritten. */ static void -clear_cursor (s) - struct screen *s; +clear_cursor (f) + struct frame *f; { int mask; - if (! s->visible - || s->phys_cursor_x < 0) + if (! FRAME_VISIBLE_P (f) + || f->phys_cursor_x < 0) return; #ifdef HAVE_X11 - x_display_cursor (s, 0); -#if 0 - XClearArea (x_current_display, s->display.x->window_desc, - s->phys_cursor_x * FONT_WIDTH (s->display.x->font) - + s->display.x->internal_border_width, - s->phys_cursor_y * FONT_HEIGHT (s->display.x->font) - + s->display.x->internal_border_width, - FONT_WIDTH (s->display.x->font) + 1, FONT_HEIGHT (s->display.x->font) + 1, False); -#endif -#else - XPixSet (s->display.x->window_desc, - s->phys_cursor_x * FONT_WIDTH (s->display.x->font) + s->display.x->internal_border_width, - s->phys_cursor_y * FONT_HEIGHT (s->display.x->font) + s->display.x->internal_border_width, - FONT_WIDTH (s->display.x->font), FONT_HEIGHT (s->display.x->font), - s->display.x->background_pixel); -#endif /* HAVE_X11 */ - s->phys_cursor_x = -1; + x_display_cursor (f, 0); +#else /* ! defined (HAVE_X11) */ + 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), + f->display.x->background_pixel); +#endif /* ! defined (HAVE_X11) */ + f->phys_cursor_x = -1; +} + +/* Redraw the glyph at ROW, COLUMN on frame F, in the style + HIGHLIGHT. HIGHLIGHT is as defined for dumpglyphs. Return the + glyph drawn. */ + +static void +x_draw_single_glyph (f, row, column, glyph, highlight) + struct frame *f; + int row, column; + GLYPH glyph; + int highlight; +{ + dumpglyphs (f, + CHAR_TO_PIXEL_COL (f, column), + CHAR_TO_PIXEL_ROW (f, row), + &glyph, 1, highlight); } static void -x_display_bar_cursor (s, on) - struct screen *s; +x_display_bar_cursor (f, on) + struct frame *f; int on; { - register int phys_x = s->phys_cursor_x; - register int phys_y = s->phys_cursor_y; - register int x1; - register int y1; - register int y2; + struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f); - if (! s->visible || (! on && s->phys_cursor_x < 0)) + /* This is pointless on invisible frames, and dangerous on garbaged + frames; in the latter case, the frame may be in the midst of + changing its size, and curs_x and curs_y may be off the frame. */ + if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f)) return; -#ifdef HAVE_X11 - if (phys_x >= 0 && - (!on || phys_x != s->cursor_x || phys_y != s->cursor_y)) - { - x1 = phys_x * FONT_WIDTH (s->display.x->font) - + s->display.x->internal_border_width; - y1 = phys_y * FONT_HEIGHT (s->display.x->font) - + s->display.x->internal_border_width - 1; - y2 = y1 + FONT_HEIGHT (s->display.x->font) + 1; + if (! on && f->phys_cursor_x < 0) + return; - XDrawLine (x_current_display, s->display.x->window_desc, - s->display.x->reverse_gc, x1, y1, x1, y2); + /* If we're not updating, then we want to use the current frame's + cursor position, not our local idea of where the cursor ought to be. */ + if (f != updating_frame) + { + curs_x = FRAME_CURSOR_X (f); + curs_y = FRAME_CURSOR_Y (f); + } - s->phys_cursor_x = phys_x = -1; + /* If there is anything wrong with the current cursor state, remove it. */ + if (f->phys_cursor_x >= 0 + && (!on + || f->phys_cursor_x != curs_x + || f->phys_cursor_y != curs_y + || f->display.x->current_cursor != bar_cursor)) + { + /* 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, + current_glyphs->highlight[f->phys_cursor_y]); + f->phys_cursor_x = -1; } - if (on && s == x_highlight_screen) + /* If we now need a cursor in the new place or in the new form, do it so. */ + if (on + && (f->phys_cursor_x < 0 + || (f->display.x->current_cursor != bar_cursor))) { - x1 = s->cursor_x * FONT_WIDTH (s->display.x->font) - + s->display.x->internal_border_width; - y1 = s->cursor_y * FONT_HEIGHT (s->display.x->font) - + s->display.x->internal_border_width - 1; - y2 = y1 + FONT_HEIGHT (s->display.x->font) + 1; + f->phys_cursor_glyph + = ((current_glyphs->enable[curs_y] + && curs_x < current_glyphs->used[curs_y]) + ? current_glyphs->glyphs[curs_y][curs_x] + : SPACEGLYPH); + XFillRectangle (x_current_display, FRAME_X_WINDOW (f), + 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)); - XDrawLine (x_current_display, s->display.x->window_desc, - s->display.x->cursor_gc, x1, y1, x1, y2); + f->phys_cursor_x = curs_x; + f->phys_cursor_y = curs_y; - s->phys_cursor_x = s->cursor_x; - s->phys_cursor_y = s->cursor_y; + f->display.x->current_cursor = bar_cursor; } -#else /* X10 */ - Give it up, dude. -#endif /* X10 */ -} - - -/* Redraw the glyph at ROW, COLUMN on screen S, in the style - HIGHLIGHT. HIGHLIGHT is as defined for dumpglyphs. Return the - glyph drawn. */ -static void -x_draw_single_glyph (s, row, column, glyph, highlight) - struct screen *s; - int row, column; - GLYPH glyph; - int highlight; -{ - dumpglyphs (s, - (column * FONT_WIDTH (s->display.x->font) - + s->display.x->internal_border_width), - (row * FONT_HEIGHT (s->display.x->font) - + s->display.x->internal_border_width), - &glyph, 1, highlight, s->display.x->font); + if (updating_frame != f) + XFlushQueue (); } -/* Turn the displayed cursor of screen S on or off according to ON. + +/* Turn the displayed cursor of frame F on or off according to ON. If ON is nonzero, where to put the cursor is specified - by S->cursor_x and S->cursor_y. */ + by F->cursor_x and F->cursor_y. */ static void -x_display_box_cursor (s, on) - struct screen *s; +x_display_box_cursor (f, on) + struct frame *f; int on; { - struct screen_glyphs *current_glyphs = SCREEN_CURRENT_GLYPHS (s); - - /* If we're not updating, then we want to use the current screen's - cursor position, not our local idea of where the cursor ought to be. */ - if (s != updating_screen) - { - curs_x = SCREEN_CURSOR_X (s); - curs_y = SCREEN_CURSOR_Y (s); - } + struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f); - if (! s->visible) + /* This is pointless on invisible frames, and dangerous on garbaged + frames; in the latter case, the frame may be in the midst of + changing its size, and curs_x and curs_y may be off the frame. */ + if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f)) return; /* If cursor is off and we want it off, return quickly. */ - if (!on && s->phys_cursor_x < 0) + if (!on && f->phys_cursor_x < 0) return; + /* If we're not updating, then we want to use the current frame's + cursor position, not our local idea of where the cursor ought to be. */ + if (f != updating_frame) + { + curs_x = FRAME_CURSOR_X (f); + curs_y = FRAME_CURSOR_Y (f); + } + /* If cursor is currently being shown and we don't want it to be or it is in the wrong place, or we want a hollow box and it's not so, (pout!) erase it. */ - if (s->phys_cursor_x >= 0 + if (f->phys_cursor_x >= 0 && (!on - || s->phys_cursor_x != curs_x - || s->phys_cursor_y != curs_y - || (s->display.x->text_cursor_kind != hollow_box_cursor - && (s != x_highlight_screen)))) + || f->phys_cursor_x != curs_x + || f->phys_cursor_y != curs_y + || (f->display.x->current_cursor != hollow_box_cursor + && (f != x_highlight_frame)))) { /* Erase the cursor by redrawing the character underneath it. */ - x_draw_single_glyph (s, s->phys_cursor_y, s->phys_cursor_x, - s->phys_cursor_glyph, - current_glyphs->highlight[s->phys_cursor_y]); - s->phys_cursor_x = -1; + x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x, + f->phys_cursor_glyph, + current_glyphs->highlight[f->phys_cursor_y]); + f->phys_cursor_x = -1; } /* If we want to show a cursor, or we want a box cursor and it's not so, write it in the right place. */ if (on - && (s->phys_cursor_x < 0 - || (s->display.x->text_cursor_kind != filled_box_cursor - && s == x_highlight_screen))) + && (f->phys_cursor_x < 0 + || (f->display.x->current_cursor != filled_box_cursor + && f == x_highlight_frame))) { - s->phys_cursor_glyph + f->phys_cursor_glyph = ((current_glyphs->enable[curs_y] && curs_x < current_glyphs->used[curs_y]) ? current_glyphs->glyphs[curs_y][curs_x] : SPACEGLYPH); - if (s != x_highlight_screen) + if (f != x_highlight_frame) { - x_draw_box (s); - s->display.x->text_cursor_kind = hollow_box_cursor; + x_draw_box (f); + f->display.x->current_cursor = hollow_box_cursor; } else { - x_draw_single_glyph (s, curs_y, curs_x, - s->phys_cursor_glyph, 2); - s->display.x->text_cursor_kind = filled_box_cursor; + x_draw_single_glyph (f, curs_y, curs_x, + f->phys_cursor_glyph, 2); + f->display.x->current_cursor = filled_box_cursor; } - s->phys_cursor_x = curs_x; - s->phys_cursor_y = curs_y; + f->phys_cursor_x = curs_x; + f->phys_cursor_y = curs_y; } - if (updating_screen != s) + if (updating_frame != f) XFlushQueue (); } -extern Lisp_Object Vbar_cursor; - -x_display_cursor (s, on) - struct screen *s; +x_display_cursor (f, on) + struct frame *f; int on; { - if (EQ (Vbar_cursor, Qnil)) - x_display_box_cursor (s, on); + if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor) + x_display_box_cursor (f, on); + else if (FRAME_DESIRED_CURSOR (f) == bar_cursor) + x_display_bar_cursor (f, on); else - x_display_bar_cursor (s, on); + /* Those are the only two we have implemented! */ + abort (); } /* Icons. */ -/* Refresh bitmap kitchen sink icon for screen S +/* Refresh bitmap kitchen sink icon for frame F when we get an expose event for it. */ -refreshicon (s) - struct screen *s; +refreshicon (f) + struct frame *f; { #ifdef HAVE_X11 /* Normally, the window manager handles this function. */ -#else +#else /* ! defined (HAVE_X11) */ int mask; - if (s->display.x->icon_bitmap_flag) - XBitmapBitsPut (s->display.x->icon_desc, 0, 0, sink_width, sink_height, + if (f->display.x->icon_bitmap_flag) + XBitmapBitsPut (f->display.x->icon_desc, 0, 0, sink_width, sink_height, sink_bits, BlackPixel, WHITE_PIX_DEFAULT, icon_bitmap, GXcopy, AllPlanes); else { - extern struct screen *selected_screen; + extern struct frame *selected_frame; struct Lisp_String *str; unsigned char *string; string - = XSTRING (XBUFFER (XWINDOW (s->selected_window)->buffer)->name)->data; + = XSTRING (XBUFFER (XWINDOW (f->selected_window)->buffer)->name)->data; - if (s->display.x->icon_label != string) + if (f->display.x->icon_label != string) { - s->display.x->icon_label = string; - XChangeWindow (s->display.x->icon_desc, + f->display.x->icon_label = string; + XChangeWindow (f->display.x->icon_desc, XQueryWidth (string, icon_font_info->id) + 10, icon_font_info->height + 10); } - XText (s->display.x->icon_desc, 5, 5, string, + XText (f->display.x->icon_desc, 5, 5, string, str->size, icon_font_info->id, BLACK_PIX_DEFAULT, WHITE_PIX_DEFAULT); } XFlushQueue (); -#endif /* HAVE_X11 */ +#endif /* ! defined (HAVE_X11) */ } -/* Make the x-window of screen S use the kitchen-sink icon - that's a window generated by Emacs. */ +/* Make the x-window of frame F use the gnu icon bitmap. */ int -x_bitmap_icon (s) - struct screen *s; +x_bitmap_icon (f) + struct frame *f; { int mask; Window icon_window; - if (s->display.x->window_desc == 0) + if (FRAME_X_WINDOW (f) == 0) return 1; #ifdef HAVE_X11 - if (icon_bitmap) - XFreePixmap (x_current_display, icon_bitmap); - - icon_bitmap = - XCreateBitmapFromData (x_current_display, s->display.x->window_desc, - gnu_bits, gnu_width, gnu_height); - x_wm_set_icon_pixmap (s, icon_bitmap); - s->display.x->icon_bitmap_flag = 1; -#else - if (s->display.x->icon_desc) + if (! icon_bitmap) + icon_bitmap = + XCreateBitmapFromData (x_current_display, FRAME_X_WINDOW (f), + gnu_bits, gnu_width, gnu_height); + x_wm_set_icon_pixmap (f, icon_bitmap); + f->display.x->icon_bitmap_flag = 1; +#else /* ! defined (HAVE_X11) */ + if (f->display.x->icon_desc) { - XClearIconWindow (s->display.x->window_desc); - XDestroyWindow (s->display.x->icon_desc); + XClearIconWindow (FRAME_X_WINDOW (f)); + XDestroyWindow (f->display.x->icon_desc); } - icon_window = XCreateWindow (s->display.x->parent_desc, + icon_window = XCreateWindow (f->display.x->parent_desc, 0, 0, sink_width, sink_height, 2, WhitePixmap, (Pixmap) NULL); if (icon_window == 0) return 1; - XSetIconWindow (s->display.x->window_desc, icon_window); + XSetIconWindow (FRAME_X_WINDOW (f), icon_window); XSelectInput (icon_window, ExposeWindow | UnmapWindow); - s->display.x->icon_desc = icon_window; - s->display.x->icon_bitmap_flag = 1; + f->display.x->icon_desc = icon_window; + f->display.x->icon_bitmap_flag = 1; if (icon_bitmap == 0) icon_bitmap = XStoreBitmap (sink_mask_width, sink_mask_height, sink_mask_bits); -#endif /* HAVE_X11 */ +#endif /* ! defined (HAVE_X11) */ return 0; } -/* Make the x-window of screen S use a rectangle with text. */ +/* Make the x-window of frame F use a rectangle with text. */ int -x_text_icon (s, icon_name) - struct screen *s; +x_text_icon (f, icon_name) + struct frame *f; char *icon_name; { #ifndef HAVE_X11 @@ -2776,267 +3784,201 @@ x_text_icon (s, icon_name) #ifndef WhitePixel #define WhitePixel 1 -#endif +#endif /* WhitePixel */ #ifndef BlackPixel #define BlackPixel 0 -#endif -#endif /* not HAVE_X11 */ +#endif /* BlackPixel */ +#endif /* HAVE_X11 */ - if (s->display.x->window_desc == 0) + if (FRAME_X_WINDOW (f) == 0) return 1; - if (icon_font_info == 0) - icon_font_info - = XGetFont (XGetDefault (XDISPLAY - (char *) XSTRING (invocation_name)->data, - "BodyFont")); - #ifdef HAVE_X11 if (icon_name) - s->display.x->icon_label = icon_name; + f->display.x->icon_label = icon_name; else - if (! s->display.x->icon_label) - s->display.x->icon_label = " *emacs* "; + if (! f->display.x->icon_label) + f->display.x->icon_label = " *emacs* "; - XSetIconName (x_current_display, s->display.x->window_desc, - (char *) s->display.x->icon_label); +#if 0 + XSetIconName (x_current_display, FRAME_X_WINDOW (f), + (char *) f->display.x->icon_label); +#endif - s->display.x->icon_bitmap_flag = 0; -#else - if (s->display.x->icon_desc) + f->display.x->icon_bitmap_flag = 0; + x_wm_set_icon_pixmap (f, 0); +#else /* ! defined (HAVE_X11) */ + if (icon_font_info == 0) + icon_font_info + = XGetFont (XGetDefault (XDISPLAY + (char *) XSTRING (Vinvocation_name)->data, + "BodyFont")); + + if (f->display.x->icon_desc) { - XClearIconWindow (XDISPLAY s->display.x->window_desc); - XDestroyWindow (XDISPLAY s->display.x->icon_desc); + XClearIconWindow (XDISPLAY FRAME_X_WINDOW (f)); + XDestroyWindow (XDISPLAY f->display.x->icon_desc); } if (icon_name) - s->display.x->icon_label = (unsigned char *) icon_name; + f->display.x->icon_label = (unsigned char *) icon_name; else - if (! s->display.x->icon_label) - s->display.x->icon_label = XSTRING (s->name)->data; + if (! f->display.x->icon_label) + f->display.x->icon_label = XSTRING (f->name)->data; - width = XStringWidth (s->display.x->icon_label, icon_font_info, 0, 0); - icon_window = XCreateWindow (s->display.x->parent_desc, - s->display.x->left_pos, - s->display.x->top_pos, + width = XStringWidth (f->display.x->icon_label, icon_font_info, 0, 0); + icon_window = XCreateWindow (f->display.x->parent_desc, + f->display.x->left_pos, + f->display.x->top_pos, width + 10, icon_font_info->height + 10, 2, BlackPixmap, WhitePixmap); if (icon_window == 0) return 1; - XSetIconWindow (s->display.x->window_desc, icon_window); + XSetIconWindow (FRAME_X_WINDOW (f), icon_window); XSelectInput (icon_window, ExposeWindow | ExposeRegion | UnmapWindow | ButtonPressed); - s->display.x->icon_desc = icon_window; - s->display.x->icon_bitmap_flag = 0; - s->display.x->icon_label = 0; -#endif /* HAVE_X11 */ + f->display.x->icon_desc = icon_window; + f->display.x->icon_bitmap_flag = 0; + f->display.x->icon_label = 0; +#endif /* ! defined (HAVE_X11) */ return 0; } /* Handling X errors. */ -/* A handler for SIGPIPE, when it occurs on the X server's connection. - This basically does an orderly shutdown of Emacs. */ +/* Shut down Emacs in an orderly fashion, because of a SIGPIPE on the + X server's connection, or an error reported via the X protocol. */ + static SIGTYPE -x_death_handler () +x_connection_closed () { if (_Xdebug) abort (); - else - Fkill_emacs (make_number (70)); -} - -static char *x_proto_requests[] = -{ - "CreateWindow", - "ChangeWindowAttributes", - "GetWindowAttributes", - "DestroyWindow", - "DestroySubwindows", - "ChangeSaveSet", - "ReparentWindow", - "MapWindow", - "MapSubwindows", - "UnmapWindow", - "UnmapSubwindows", - "ConfigureWindow", - "CirculateWindow", - "GetGeometry", - "QueryTree", - "InternAtom", - "GetAtomName", - "ChangeProperty", - "DeleteProperty", - "GetProperty", - "ListProperties", - "SetSelectionOwner", - "GetSelectionOwner", - "ConvertSelection", - "SendEvent", - "GrabPointer", - "UngrabPointer", - "GrabButton", - "UngrabButton", - "ChangeActivePointerGrab", - "GrabKeyboard", - "UngrabKeyboard", - "GrabKey", - "UngrabKey", - "AllowEvents", - "GrabServer", - "UngrabServer", - "QueryPointer", - "GetMotionEvents", - "TranslateCoords", - "WarpPointer", - "SetInputFocus", - "GetInputFocus", - "QueryKeymap", - "OpenFont", - "CloseFont", - "QueryFont", - "QueryTextExtents", - "ListFonts", - "ListFontsWithInfo", - "SetFontPath", - "GetFontPath", - "CreatePixmap", - "FreePixmap", - "CreateGC", - "ChangeGC", - "CopyGC", - "SetDashes", - "SetClipRectangles", - "FreeGC", - "ClearArea", - "CopyArea", - "CopyPlane", - "PolyPoint", - "PolyLine", - "PolySegment", - "PolyRectangle", - "PolyArc", - "FillPoly", - "PolyFillRectangle", - "PolyFillArc", - "PutImage", - "GetImage", - "PolyText", - "PolyText", - "ImageText", - "ImageText", - "CreateColormap", - "FreeColormap", - "CopyColormapAndFree", - "InstallColormap", - "UninstallColormap", - "ListInstalledColormaps", - "AllocColor", - "AllocNamedColor", - "AllocColorCells", - "AllocColorPlanes", - "FreeColors", - "StoreColors", - "StoreNamedColor", - "QueryColors", - "LookupColor", - "CreateCursor", - "CreateGlyphCursor", - "FreeCursor", - "RecolorCursor", - "QueryBestSize", - "QueryExtension", - "ListExtensions", - "ChangeKeyboardMapping", - "GetKeyboardMapping", - "ChangeKeyboardControl", - "GetKeyboardControl", - "Bell", - "ChangePointerControl", - "GetPointerControl", - "SetScreenSaver", - "GetScreenSaver", - "ChangeHosts", - "ListHosts", - "SetAccessControl", - "SetCloseDownMode", - "KillClient", - "RotateProperties", - "ForceScreenSaver", - "SetPointerMapping", - "GetPointerMapping", - "SetModifierMapping", - "GetModifierMapping", - "NoOperation" -}; -#define acceptable_x_error_p(type) ((type) == 94) + shut_down_emacs (0, 1, Qnil); + + exit (70); +} -x_handle_error_gracefully (event) - XErrorEvent *event; +/* An X error handler which prints an error message and then kills + Emacs. This is what's normally installed as Xlib's handler for + protocol errors. */ +static int +x_error_quitter (display, error) + Display *display; + XErrorEvent *error; { - char error_ptr[128]; - char *proto_ptr = x_proto_requests[event->request_code]; - char str[128]; + char buf[256]; + + /* Note that there is no real way portable across R3/R4 to get the + original error handler. */ + + XGetErrorText (display, error->error_code, buf, sizeof (buf)); + fprintf (stderr, "X protocol error: %s on protocol request %d\n", + buf, error->request_code); + +#if 0 + /* While we're testing Emacs 19, we'll just dump core whenever we + get an X error, so we can figure out why it happened. */ + abort (); +#endif - XGetErrorText (x_current_display, event->error_code, error_ptr, 128); - sprintf (str, "X Protocol Error: %s on request: %s", error_ptr, proto_ptr); - TOTALLY_UNBLOCK_INPUT; - error (str); + x_connection_closed (); } +/* A handler for X IO errors which prints an error message and then + kills Emacs. This is what is always installed as Xlib's handler + for I/O errors. */ +static int +x_io_error_quitter (display) + Display *display; +{ + fprintf (stderr, "Connection to X server %s lost.\n", + XDisplayName (DisplayString (display))); + #if 0 -extern int x_selection_alloc_error; -extern int x_converting_selection; + /* While we're testing Emacs 19, we'll just dump core whenever we + get an X error, so we can figure out why it happened. */ + abort (); #endif -/* Handle X Errors. If the error is not traumatic, - just call error (). Otherwise print a (hopefully) interesting - message and quit. + x_connection_closed (); +} - The arg to Fkill_emacs is an exit status value - and also prevents any questions. */ +/* A buffer for storing X error messages. */ +static char *x_caught_error_message; +#define X_CAUGHT_ERROR_MESSAGE_SIZE 200 -x_error_handler (disp, event) - Display *disp; -#ifdef HAVE_X11 - XErrorEvent *event; +/* An X error handler which stores the error message in + x_caught_error_message. This is what's installed when + x_catch_errors is in effect. */ +static int +x_error_catcher (display, error) + Display *display; + XErrorEvent *error; +{ + XGetErrorText (display, error->error_code, + x_caught_error_message, X_CAUGHT_ERROR_MESSAGE_SIZE); +} -#define XlibDisplayIOError (1L << 0) -#else - struct _XErrorEvent *event; -#endif +/* Begin trapping X errors. + + After calling this function, X protocol errors no longer cause + Emacs to exit; instead, they are recorded in x_cfc_error_message. + + Calling x_check_errors signals an Emacs error if an X error has + occurred since the last call to x_catch_errors or x_check_errors. + + Calling x_uncatch_errors resumes the normal error handling. */ + +void x_catch_errors(), x_check_errors (), x_uncatch_errors (); + +void +x_catch_errors () { - /* Here we use the standard X handlers. */ + /* Make sure any errors from previous requests have been dealt with. */ + XSync (x_current_display, False); - BLOCK_INPUT; - if (event && event->type == 0) /* 0 is the XError Event type. */ - { -#if 0 -#ifdef HAVE_X11 - if (event->request_code == BadAlloc && x_converting_selection) - x_selection_alloc_error = 1; - else -#endif -#endif - if (acceptable_x_error_p (event->request_code)) - x_handle_error_gracefully (event); - else - _XDefaultError (disp, event); - } - else + /* Set up the error buffer. */ + x_caught_error_message + = (char*) xmalloc (X_CAUGHT_ERROR_MESSAGE_SIZE); + x_caught_error_message[0] = '\0'; + + /* Install our little error handler. */ + XHandleError (x_error_catcher); +} + +/* If any X protocol errors have arrived since the last call to + x_catch_errors or x_check_errors, signal an Emacs error using + sprintf (a buffer, FORMAT, the x error message text) as the text. */ +void +x_check_errors (format) + char *format; +{ + /* Make sure to catch any errors incurred so far. */ + XSync (x_current_display, False); + + if (x_caught_error_message[0]) { - disp->flags |= XlibDisplayIOError; - _XDefaultIOError (disp); + char buf[X_CAUGHT_ERROR_MESSAGE_SIZE + 56]; + + sprintf (buf, format, x_caught_error_message); + x_uncatch_errors (); + error (buf); } - UNBLOCK_INPUT; +} - x_death_handler (); +void +x_uncatch_errors () +{ + xfree (x_caught_error_message); + x_caught_error_message = 0; + XHandleError (x_error_quitter); } #if 0 @@ -3045,17 +3987,25 @@ x_trace_wire () { fprintf (stderr, "Lib call: %d\n", ++x_wire_count); } -#endif +#endif /* ! 0 */ -/* Set the font of the x-window specified by screen S +/* Changing the font of the frame. */ + +/* Set the font of the x-window specified by frame F to the font named NEWNAME. This is safe to use - even before S has an actual x-window. */ + even before F has an actual x-window. */ #ifdef HAVE_X11 +struct font_info +{ + XFontStruct *font; + char *name; +}; + /* A table of all the fonts we have already loaded. */ -static XFontStruct **x_font_table; +static struct font_info *x_font_table; /* The current capacity of x_font_table. */ static int x_font_table_size; @@ -3065,11 +4015,11 @@ static int x_font_table_size; 0 <= n_fonts <= x_font_table_size. */ static int n_fonts; -x_new_font (s, fontname) - struct screen *s; +Lisp_Object +x_new_font (f, fontname) + struct frame *f; register char *fontname; { - XFontStruct *temp; int already_loaded; int n_matching_fonts; XFontStruct *font_info; @@ -3078,85 +4028,117 @@ x_new_font (s, fontname) /* Get a list of all the fonts that match this name. Once we have a list of matching fonts, we compare them against the fonts we already have by comparing font ids. */ - font_names = (char **) XListFontsWithInfo (x_current_display, fontname, - 1024, &n_matching_fonts, - &font_info); - /* If the server couldn't find any fonts whose named matched fontname, - return an error code. */ - if (n_matching_fonts == 0) - return 1; + font_names = (char **) XListFonts (x_current_display, fontname, + 1024, &n_matching_fonts); + /* Apparently it doesn't set n_matching_fonts to zero when it can't + find any matches; font_names == 0 is the only clue. */ + if (! font_names) + n_matching_fonts = 0; + + /* Don't just give up if n_matching_fonts is 0. + Apparently there's a bug on Suns: XListFontsWithInfo can + fail to find a font, but XLoadQueryFont may still find it. */ /* See if we've already loaded a matching font. */ - { - int i, j; + already_loaded = -1; + if (n_matching_fonts != 0) + { + int i, j; - already_loaded = 0; - for (i = 0; i < n_fonts; i++) - for (j = 0; j < n_matching_fonts; j++) - if (x_font_table[i]->fid == font_info[j].fid) - { - already_loaded = i; - goto found_font; - } - } + for (i = 0; i < n_fonts; i++) + for (j = 0; j < n_matching_fonts; j++) + if (!strcmp (x_font_table[i].name, font_names[j])) + { + already_loaded = i; + fontname = font_names[j]; + goto found_font; + } + } found_font: /* If we have, just return it from the table. */ - if (already_loaded) - s->display.x->font = x_font_table[already_loaded]; + if (already_loaded >= 0) + f->display.x->font = x_font_table[already_loaded].font; /* Otherwise, load the font and add it to the table. */ else { + int i; XFontStruct *font; + /* Try to find a character-cell font in the list. */ +#if 0 + /* A laudable goal, but this isn't how to do it. */ + for (i = 0; i < n_matching_fonts; i++) + if (! font_info[i].per_char) + break; +#else + i = 0; +#endif + + /* See comment above. */ + if (n_matching_fonts != 0) + fontname = font_names[i]; + font = (XFontStruct *) XLoadQueryFont (x_current_display, fontname); if (! font) - return 1; + { + /* Free the information from XListFonts. */ + if (n_matching_fonts) + XFreeFontNames (font_names); + return Qnil; + } /* Do we need to create the table? */ if (x_font_table_size == 0) { x_font_table_size = 16; x_font_table - = (XFontStruct **) xmalloc (x_font_table_size - * sizeof (x_font_table[0])); + = (struct font_info *) xmalloc (x_font_table_size + * sizeof (x_font_table[0])); } /* Do we need to grow the table? */ else if (n_fonts >= x_font_table_size) { x_font_table_size *= 2; x_font_table - = (XFontStruct **) xrealloc (x_font_table, - (x_font_table_size - * sizeof (x_font_table[0]))); + = (struct font_info *) xrealloc (x_font_table, + (x_font_table_size + * sizeof (x_font_table[0]))); } - s->display.x->font = x_font_table[n_fonts++] = font; + x_font_table[n_fonts].name = (char *) xmalloc (strlen (fontname)); + bcopy (fontname, x_font_table[n_fonts].name, strlen (fontname) + 1); + f->display.x->font = x_font_table[n_fonts++].font = font; } - - /* Free the information from XListFontsWithInfo. The data - we actually retain comes from XLoadQueryFont. */ - XFreeFontInfo (font_names, font_info, n_matching_fonts); - /* Now make the screen display the given font. */ - if (s->display.x->window_desc != 0) + /* Now make the frame display the given font. */ + if (FRAME_X_WINDOW (f) != 0) { - XSetFont (x_current_display, s->display.x->normal_gc, - s->display.x->font->fid); - XSetFont (x_current_display, s->display.x->reverse_gc, - s->display.x->font->fid); - XSetFont (x_current_display, s->display.x->cursor_gc, - s->display.x->font->fid); - - x_set_window_size (s, s->width, s->height); + XSetFont (x_current_display, f->display.x->normal_gc, + f->display.x->font->fid); + XSetFont (x_current_display, f->display.x->reverse_gc, + f->display.x->font->fid); + XSetFont (x_current_display, f->display.x->cursor_gc, + f->display.x->font->fid); + + x_set_window_size (f, f->width, f->height); } - return 0; + { + Lisp_Object lispy_name = build_string (fontname); + + + /* Free the information from XListFonts. The data + we actually retain comes from XLoadQueryFont. */ + XFreeFontNames (font_names); + + return lispy_name; + } } -#else -x_new_font (s, newname) - struct screen *s; +#else /* ! defined (HAVE_X11) */ +x_new_font (f, newname) + struct frame *f; register char *newname; { FONT_TYPE *temp; @@ -3166,219 +4148,274 @@ x_new_font (s, newname) if (temp == (FONT_TYPE *) 0) return 1; - if (s->display.x->font) - XLoseFont (s->display.x->font); + if (f->display.x->font) + XLoseFont (f->display.x->font); - s->display.x->font = temp; + f->display.x->font = temp; - if (s->display.x->window_desc != 0) - x_set_window_size (s, s->width, s->height); + if (FRAME_X_WINDOW (f) != 0) + x_set_window_size (f, f->width, f->height); return 0; } -#endif +#endif /* ! defined (HAVE_X11) */ -x_calc_absolute_position (s) - struct screen *s; +/* X Window sizes and positions. */ + +x_calc_absolute_position (f) + struct frame *f; { #ifdef HAVE_X11 - if (s->display.x->left_pos < 0) - s->display.x->left_pos - = XINT (x_screen_width) - PIXEL_WIDTH (s) + s->display.x->left_pos; - - if (s->display.x->top_pos < 0) - s->display.x->top_pos - = XINT (x_screen_height) - PIXEL_HEIGHT (s) + s->display.x->top_pos; -#else /* X10 */ + Window win, child; + int win_x = 0, win_y = 0; + + /* Find the position of the outside upper-left corner of + the inner window, with respect to the outer window. */ + if (f->display.x->parent_desc != ROOT_WINDOW) + { + BLOCK_INPUT; + XTranslateCoordinates (x_current_display, + + /* From-window, to-window. */ + f->display.x->window_desc, + f->display.x->parent_desc, + + /* From-position, to-position. */ + 0, 0, &win_x, &win_y, + + /* Child of win. */ + &child); + UNBLOCK_INPUT; + } + + /* Treat negative positions as relative to the leftmost bottommost + position that fits on the screen. */ + if (f->display.x->left_pos < 0) + f->display.x->left_pos = (x_screen_width + - f->display.x->border_width - win_x + - PIXEL_WIDTH (f) + + f->display.x->left_pos); + + if (f->display.x->top_pos < 0) + f->display.x->top_pos = (x_screen_height + - f->display.x->border_width - win_y + - PIXEL_HEIGHT (f) + + f->display.x->top_pos); + +#else /* ! defined (HAVE_X11) */ WINDOWINFO_TYPE parentinfo; - XGetWindowInfo (s->display.x->window_desc, &parentinfo); + XGetWindowInfo (FRAME_X_WINDOW (f), &parentinfo); - if (s->display.x->left_pos < 0) - s->display.x->left_pos = parentinfo.width + (s->display.x->left_pos + 1) - - PIXEL_WIDTH (s) - 2 * s->display.x->internal_border_width; + if (f->display.x->left_pos < 0) + f->display.x->left_pos = parentinfo.width + (f->display.x->left_pos + 1) + - PIXEL_WIDTH (f) - 2 * f->display.x->internal_border_width; - if (s->display.x->top_pos < 0) - s->display.x->top_pos = parentinfo.height + (s->display.x->top_pos + 1) - - PIXEL_HEIGHT (s) - 2 * s->display.x->internal_border_width; -#endif /* X10 */ + if (f->display.x->top_pos < 0) + f->display.x->top_pos = parentinfo.height + (f->display.x->top_pos + 1) + - PIXEL_HEIGHT (f) - 2 * f->display.x->internal_border_width; +#endif /* ! defined (HAVE_X11) */ } -x_set_offset (s, xoff, yoff) - struct screen *s; +x_set_offset (f, xoff, yoff) + struct frame *f; register int xoff, yoff; { - s->display.x->top_pos = yoff; - s->display.x->left_pos = xoff; - x_calc_absolute_position (s); + f->display.x->top_pos = yoff; + f->display.x->left_pos = xoff; + x_calc_absolute_position (f); BLOCK_INPUT; - XMoveWindow (XDISPLAY s->display.x->window_desc, - s->display.x->left_pos, s->display.x->top_pos); + XMoveWindow (XDISPLAY FRAME_X_WINDOW (f), + f->display.x->left_pos, f->display.x->top_pos); #ifdef HAVE_X11 - x_wm_set_size_hint (s, 0); -#endif + x_wm_set_size_hint (f, 0, xoff, yoff); +#endif /* ! defined (HAVE_X11) */ UNBLOCK_INPUT; } -/* Call this to change the size of screen S's x-window. */ +/* Call this to change the size of frame F's x-window. */ -x_set_window_size (s, cols, rows) - struct screen *s; - register int cols, rows; +x_set_window_size (f, cols, rows) + struct frame *f; + int cols, rows; { int pixelwidth, pixelheight; int mask; - int ibw = s->display.x->internal_border_width; BLOCK_INPUT; - /* ??? Who DOES worry about minimum reasonable sizes? */ - pixelwidth = (cols * FONT_WIDTH (s->display.x->font) + 2 * ibw - + s->display.x->v_scrollbar_width); - pixelheight = (rows * FONT_HEIGHT (s->display.x->font) + 2 * ibw - + s->display.x->h_scrollbar_height); + check_frame_size (f, &rows, &cols); + f->display.x->vertical_scroll_bar_extra + = (FRAME_HAS_VERTICAL_SCROLL_BARS (f) + ? VERTICAL_SCROLL_BAR_PIXEL_WIDTH (f) + : 0); + pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols); + pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows); #ifdef HAVE_X11 - x_wm_set_size_hint (s, 0); -#endif /* HAVE_X11 */ - XChangeWindowSize (s->display.x->window_desc, pixelwidth, pixelheight); + x_wm_set_size_hint (f, 0, 0, 0); +#endif /* ! defined (HAVE_X11) */ + XChangeWindowSize (FRAME_X_WINDOW (f), pixelwidth, pixelheight); + + /* Now, strictly speaking, we can't be sure that this is accurate, + but the window manager will get around to dealing with the size + change request eventually, and we'll hear how it went when the + ConfigureNotify event gets here. + + We could just not bother storing any of this information here, + and let the ConfigureNotify event set everything up, but that + might be kind of confusing to the lisp code, since size changes + wouldn't be reported in the frame parameters until some random + point in the future when the ConfigureNotify event arrives. */ + change_frame_size (f, rows, cols, 0, 0); + PIXEL_WIDTH (f) = pixelwidth; + PIXEL_HEIGHT (f) = pixelheight; + + /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to + receive in the ConfigureNotify event; if we get what we asked + for, then the event won't cause the screen to become garbaged, so + we have to make sure to do it here. */ + SET_FRAME_GARBAGED (f); + XFlushQueue (); UNBLOCK_INPUT; } #ifndef HAVE_X11 -x_set_resize_hint (s) - struct screen *s; +x_set_resize_hint (f) + struct frame *f; { - - XSetResizeHint (s->display.x->window_desc, 2 * s->display.x->internal_border_width, - 2 * s->display.x->internal_border_width, - FONT_WIDTH (s->display.x->font), FONT_HEIGHT (s->display.x->font)); + XSetResizeHint (FRAME_X_WINDOW (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)); } -#endif /* not HAVE_X11 */ +#endif /* HAVE_X11 */ +/* Mouse warping, focus shifting, raising and lowering. */ -x_set_mouse_position (s, x, y) - struct screen *s; +x_set_mouse_position (f, x, y) + struct frame *f; int x, y; { int pix_x, pix_y; - x_raise_screen (s); + x_raise_frame (f); - if (x < 0) - pix_x = (SCREEN_WIDTH (s) - * FONT_WIDTH (s->display.x->font) - + 2 * s->display.x->internal_border_width - + s->display.x->v_scrollbar_width) / 2; - else - pix_x = x * FONT_WIDTH (s->display.x->font) + 2; /* add 2 pixels to each - dimension to move the - mouse into the char - cell */ - - if (y < 0) - pix_y = (SCREEN_HEIGHT (s) - * FONT_HEIGHT (s->display.x->font) - + 2 * s->display.x->internal_border_width - + s->display.x->h_scrollbar_height) / 2; - else - pix_y = y * FONT_HEIGHT (s->display.x->font) + 2; + 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; + + if (pix_x < 0) pix_x = 0; + if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f); + + if (pix_y < 0) pix_y = 0; + if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f); BLOCK_INPUT; - x_mouse_x = x; - x_mouse_y = y; - XWarpMousePointer (s->display.x->window_desc, pix_x, pix_y); + XWarpMousePointer (FRAME_X_WINDOW (f), pix_x, pix_y); UNBLOCK_INPUT; } #ifdef HAVE_X11 -x_focus_on_screen (s) - struct screen *s; +x_focus_on_frame (f) + struct frame *f; { - x_raise_screen (s); + x_raise_frame (f); #if 0 /* I don't think that the ICCCM allows programs to do things like this without the interaction of the window manager. Whatever you end up - doing with this code, do it to x_unfocus_screen too. */ - XSetInputFocus (x_current_display, s->display.x->window_desc, + doing with this code, do it to x_unfocus_frame too. */ + XSetInputFocus (x_current_display, FRAME_X_WINDOW (f), RevertToPointerRoot, CurrentTime); -#endif +#endif /* ! 0 */ } -x_unfocus_screen (s) - struct screen *s; +x_unfocus_frame (f) + struct frame *f; { #if 0 - /* Look at the remarks in x_focus_on_screen. */ - if (x_focus_screen == s) + /* Look at the remarks in x_focus_on_frame. */ + if (x_focus_frame == f) XSetInputFocus (x_current_display, PointerRoot, RevertToPointerRoot, CurrentTime); -#endif +#endif /* ! 0 */ } -#endif +#endif /* ! defined (HAVE_X11) */ -/* Raise screen S. */ +/* Raise frame F. */ -x_raise_screen (s) - struct screen *s; +x_raise_frame (f) + struct frame *f; { - if (s->visible) + if (f->async_visible) { BLOCK_INPUT; - XRaiseWindow (XDISPLAY s->display.x->window_desc); + XRaiseWindow (XDISPLAY FRAME_X_WINDOW (f)); XFlushQueue (); UNBLOCK_INPUT; } } -/* Lower screen S. */ +/* Lower frame F. */ -x_lower_screen (s) - struct screen *s; +x_lower_frame (f) + struct frame *f; { - if (s->visible) + if (f->async_visible) { BLOCK_INPUT; - XLowerWindow (XDISPLAY s->display.x->window_desc); + XLowerWindow (XDISPLAY FRAME_X_WINDOW (f)); XFlushQueue (); UNBLOCK_INPUT; } } +static void +XTframe_raise_lower (f, raise) + FRAME_PTR f; + int raise; +{ + if (raise) + x_raise_frame (f); + else + x_lower_frame (f); +} + + /* Change from withdrawn state to mapped state. */ -x_make_screen_visible (s) - struct screen *s; +x_make_frame_visible (f) + struct frame *f; { int mask; BLOCK_INPUT; - if (! SCREEN_VISIBLE_P (s)) + if (! FRAME_VISIBLE_P (f)) { #ifdef HAVE_X11 if (! EQ (Vx_no_window_manager, Qt)) - x_wm_set_window_state (s, NormalState); + x_wm_set_window_state (f, NormalState); - XMapWindow (XDISPLAY s->display.x->window_desc); - if (s->display.x->v_scrollbar != 0 || s->display.x->h_scrollbar != 0) - XMapSubwindows (x_current_display, s->display.x->window_desc); -#else - XMapWindow (XDISPLAY s->display.x->window_desc); - if (s->display.x->icon_desc != 0) - XUnmapWindow (s->display.x->icon_desc); + XMapWindow (XDISPLAY FRAME_X_WINDOW (f)); + if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)) + XMapSubwindows (x_current_display, FRAME_X_WINDOW (f)); +#else /* ! defined (HAVE_X11) */ + XMapWindow (XDISPLAY FRAME_X_WINDOW (f)); + if (f->display.x->icon_desc != 0) + XUnmapWindow (f->display.x->icon_desc); /* Handled by the MapNotify event for X11 */ - s->visible = 1; - s->iconified = 0; + f->async_visible = 1; + f->async_iconified = 0; - /* NOTE: this may cause problems for the first screen. */ + /* NOTE: this may cause problems for the first frame. */ XTcursor_to (0, 0); -#endif /* not HAVE_X11 */ +#endif /* ! defined (HAVE_X11) */ } XFlushQueue (); @@ -3388,142 +4425,164 @@ x_make_screen_visible (s) /* Change from mapped state to withdrawn state. */ -x_make_screen_invisible (s) - struct screen *s; +x_make_frame_invisible (f) + struct frame *f; { int mask; - if (! s->visible) + /* Don't keep the highlight on an invisible frame. */ + if (x_highlight_frame == f) + x_highlight_frame = 0; + + if (! f->async_visible && ! f->async_iconified) return; BLOCK_INPUT; + +#ifdef HAVE_X11R4 + + if (! XWithdrawWindow (x_current_display, FRAME_X_WINDOW (f), + DefaultScreen (x_current_display))) + { + UNBLOCK_INPUT_RESIGNAL; + error ("can't notify window manager of window withdrawal"); + } + +#else /* ! defined (HAVE_X11R4) */ #ifdef HAVE_X11 -#if 0 + + /* Tell the window manager what we're going to do. */ if (! EQ (Vx_no_window_manager, Qt)) { - XUnmapEvent unmap; + XEvent unmap; - unmap.type = UnmapNotify; - unmap.window = s->display.x->window_desc; - unmap.event = DefaultRootWindow (x_current_display); - unmap.from_configure = False; - XSendEvent (x_current_display, DefaultRootWindow (x_current_display), - False, SubstructureRedirectMask|SubstructureNotifyMask, - &unmap); + unmap.xunmap.type = UnmapNotify; + unmap.xunmap.window = FRAME_X_WINDOW (f); + unmap.xunmap.event = DefaultRootWindow (x_current_display); + unmap.xunmap.from_configure = False; + if (! XSendEvent (x_current_display, + DefaultRootWindow (x_current_display), + False, + SubstructureRedirectMask|SubstructureNotifyMask, + &unmap)) + { + UNBLOCK_INPUT_RESIGNAL; + error ("can't notify window manager of withdrawal"); + } } - /* The new function below does the same as the above code, plus unmapping - the window. Sending the event without actually unmapping can make - the window manager start ignoring the window (i.e., no more title bar, - icon manager stuff.) */ -#endif + /* Unmap the window ourselves. Cheeky! */ + XUnmapWindow (x_current_display, FRAME_X_WINDOW (f)); - /* New function available with R4 */ - if (! XWithdrawWindow (x_current_display, s->display.x->window_desc, - DefaultScreen (x_current_display))) - { - UNBLOCK_INPUT_RESIGNAL; - error ("Can't notify window manager of iconification."); - } +#else /* ! defined (HAVE_X11) */ -#else - XUnmapWindow (XDISPLAY s->display.x->window_desc); + XUnmapWindow (FRAME_X_WINDOW (f)); + f->async_visible = 0; /* Handled by the UnMap event for X11 */ + if (f->display.x->icon_desc != 0) + XUnmapWindow (f->display.x->icon_desc); - s->visible = 0; /* Handled by the UnMap event for X11 */ - if (s->display.x->icon_desc != 0) - XUnmapWindow (XDISPLAY s->display.x->icon_desc); -#endif /* not HAVE_X11 */ +#endif /* ! defined (HAVE_X11) */ +#endif /* ! defined (HAVE_X11R4) */ XFlushQueue (); UNBLOCK_INPUT; } - /* Window manager communication. Created in Fx_open_connection. */ -extern Atom Xatom_wm_change_state; - /* Change window state from mapped to iconified. */ -x_iconify_screen (s) - struct screen *s; +x_iconify_frame (f) + struct frame *f; { int mask; - if (s->iconified) + /* Don't keep the highlight on an invisible frame. */ + if (x_highlight_frame == f) + x_highlight_frame = 0; + + if (f->async_iconified) return; BLOCK_INPUT; #ifdef HAVE_X11 - if (! EQ (Vx_no_window_manager, Qt)) - if (! XIconifyWindow (x_current_display, s->display.x->window_desc, - DefaultScreen (x_current_display))) + /* Since we don't know which revision of X we're running, we'll use both + the X11R3 and X11R4 techniques. I don't know if this is a good idea. */ + + /* X11R4: send a ClientMessage to the window manager using the + WM_CHANGE_STATE type. */ + { + XEvent message; + + message.xclient.window = FRAME_X_WINDOW (f); + message.xclient.type = ClientMessage; + message.xclient.message_type = Xatom_wm_change_state; + message.xclient.format = 32; + message.xclient.data.l[0] = IconicState; + + if (! XSendEvent (x_current_display, + DefaultRootWindow (x_current_display), + False, + SubstructureRedirectMask | SubstructureNotifyMask, + &message)) { UNBLOCK_INPUT_RESIGNAL; error ("Can't notify window manager of iconification."); } + } - s->iconified = 1; - -#if 0 - { - XClientMessageEvent message; - - message.window = s->display.x->window_desc; - message.type = ClientMessage; - message.message_type = Xatom_wm_change_state; - message.format = 32; - message.data.l[0] = IconicState; + /* X11R3: set the initial_state field of the window manager hints to + IconicState. */ + x_wm_set_window_state (f, IconicState); - if (! XSendEvent (x_current_display, - DefaultRootWindow (x_current_display), - False, - SubstructureRedirectMask | SubstructureNotifyMask, - &message)) - { - UNBLOCK_INPUT_RESIGNAL; - error ("Can't notify window manager of iconification."); - } + if (!FRAME_VISIBLE_P (f)) + { + /* If the frame was withdrawn, before, we must map it. */ + XMapWindow (XDISPLAY FRAME_X_WINDOW (f)); + if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)) + XMapSubwindows (x_current_display, FRAME_X_WINDOW (f)); } -#endif -#else /* X10 */ - XUnmapWindow (XDISPLAY s->display.x->window_desc); - s->visible = 0; /* Handled in the UnMap event for X11. */ - if (s->display.x->icon_desc != 0) + f->async_iconified = 1; +#else /* ! defined (HAVE_X11) */ + XUnmapWindow (XDISPLAY FRAME_X_WINDOW (f)); + + f->async_visible = 0; /* Handled in the UnMap event for X11. */ + if (f->display.x->icon_desc != 0) { - XMapWindow (XDISPLAY s->display.x->icon_desc); - refreshicon (s); + XMapWindow (XDISPLAY f->display.x->icon_desc); + refreshicon (f); } -#endif /* X10 */ +#endif /* ! defined (HAVE_X11) */ XFlushQueue (); UNBLOCK_INPUT; } -/* Destroy the X window of screen S. - DISPL is the former s->display (since s->display - has already been nulled out). */ +/* Destroy the X window of frame F. */ -x_destroy_window (s, displ) - struct screen *s; - union display displ; +x_destroy_window (f) + struct frame *f; { - int mask; - BLOCK_INPUT; - if (displ.x->icon_desc != 0) - XDestroyWindow (XDISPLAY displ.x->icon_desc); - XDestroyWindow (XDISPLAY displ.x->window_desc); + + if (f->display.x->icon_desc != 0) + XDestroyWindow (XDISPLAY f->display.x->icon_desc); + XDestroyWindow (XDISPLAY f->display.x->window_desc); + free_frame_faces (f); XFlushQueue (); - UNBLOCK_INPUT; - free (displ.x); - if (s == x_focus_screen) - x_focus_screen = 0; - if (s == x_highlight_screen) - x_highlight_screen = 0; + xfree (f->display.x); + f->display.x = 0; + if (f == x_focus_frame) + x_focus_frame = 0; + if (f == x_highlight_frame) + x_highlight_frame = 0; + + UNBLOCK_INPUT; } +/* Manage event queues for X10. */ + #ifndef HAVE_X11 /* Manage event queues. @@ -3594,39 +4653,70 @@ mouse_event_pending_p () { return queue_event_count (&x_mouse_queue); } -#endif +#endif /* HAVE_X11 */ +/* Setting window manager hints. */ + #ifdef HAVE_X11 -x_wm_set_size_hint (s, prompting) - struct screen *s; +/* SPEC_X and SPEC_Y are the specified positions. + We look only at their sign, to decide the gravity. */ + +x_wm_set_size_hint (f, prompting, spec_x, spec_y) + struct frame *f; long prompting; + int spec_x, spec_y; { XSizeHints size_hints; - Window window = s->display.x->window_desc; - - size_hints.flags = PResizeInc | PMinSize | PMaxSize; - - flexlines = s->height; - - size_hints.x = s->display.x->left_pos; - size_hints.y = s->display.x->top_pos; - size_hints.height = PIXEL_HEIGHT (s); - size_hints.width = PIXEL_WIDTH (s); - size_hints.width_inc = FONT_WIDTH (s->display.x->font); - size_hints.height_inc = FONT_HEIGHT (s->display.x->font); - size_hints.base_width = (2 * s->display.x->internal_border_width) - + s->display.x->v_scrollbar_width; - size_hints.base_height = (2 * s->display.x->internal_border_width) - + s->display.x->h_scrollbar_height; - size_hints.min_width = size_hints.base_width + size_hints.width_inc; - size_hints.min_height = size_hints.base_height + size_hints.height_inc; - size_hints.max_width = x_screen_width - - ((2 * s->display.x->internal_border_width) - + s->display.x->v_scrollbar_width); - size_hints.max_height = x_screen_height - - ((2 * s->display.x->internal_border_width) - + s->display.x->h_scrollbar_height); + Window window = FRAME_X_WINDOW (f); + + size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */; + + flexlines = f->height; + + size_hints.x = f->display.x->left_pos; + size_hints.y = f->display.x->top_pos; + size_hints.height = PIXEL_HEIGHT (f); + size_hints.width = PIXEL_WIDTH (f); + 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 + { + int base_width, base_height; + + 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. + + 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; +#else + size_hints.min_width = base_width; + size_hints.min_height = base_height; +#endif + } + + } if (prompting) size_hints.flags |= prompting; @@ -3634,7 +4724,8 @@ x_wm_set_size_hint (s, prompting) { XSizeHints hints; /* Sometimes I hate X Windows... */ - XGetNormalHints (x_current_display, window, &hints); + if (XGetNormalHints (x_current_display, window, &hints) == 0) + hints.flags = 0; if (hints.flags & PSize) size_hints.flags |= PSize; if (hints.flags & PPosition) @@ -3644,80 +4735,106 @@ x_wm_set_size_hint (s, prompting) if (hints.flags & USSize) size_hints.flags |= USSize; } - -#if 0 /* R3 */ + + switch (((spec_x < 0) << 1) + (spec_y < 0)) + { + case 0: + size_hints.win_gravity = NorthWestGravity; + break; + case 1: + size_hints.win_gravity = SouthWestGravity; + break; + case 2: + size_hints.win_gravity = NorthEastGravity; + break; + case 3: + size_hints.win_gravity = SouthEastGravity; + break; + } + size_hints.flags |= PWinGravity; + +#ifdef HAVE_X11R4 + XSetWMNormalHints (x_current_display, window, &size_hints); +#else XSetNormalHints (x_current_display, window, &size_hints); #endif - XSetWMNormalHints (x_current_display, window, &size_hints); } /* Used for IconicState or NormalState */ -x_wm_set_window_state (s, state) - struct screen *s; +x_wm_set_window_state (f, state) + struct frame *f; int state; { - XWMHints wm_hints; - Window window = s->display.x->window_desc; + Window window = FRAME_X_WINDOW (f); + + f->display.x->wm_hints.flags |= StateHint; + f->display.x->wm_hints.initial_state = state; - wm_hints.flags = StateHint; - wm_hints.initial_state = state; - XSetWMHints (x_current_display, window, &wm_hints); + XSetWMHints (x_current_display, window, &f->display.x->wm_hints); } -x_wm_set_icon_pixmap (s, icon_pixmap) - struct screen *s; +x_wm_set_icon_pixmap (f, icon_pixmap) + struct frame *f; Pixmap icon_pixmap; { - XWMHints wm_hints; - Window window = s->display.x->window_desc; + Window window = FRAME_X_WINDOW (f); + + if (icon_pixmap) + { + f->display.x->wm_hints.icon_pixmap = icon_pixmap; + f->display.x->wm_hints.flags |= IconPixmapHint; + } + else + f->display.x->wm_hints.flags &= ~IconPixmapHint; - wm_hints.flags = IconPixmapHint; - wm_hints.icon_pixmap = icon_pixmap; - XSetWMHints (x_current_display, window, &wm_hints); + XSetWMHints (x_current_display, window, &f->display.x->wm_hints); } -x_wm_set_icon_position (s, icon_x, icon_y) - struct screen *s; +x_wm_set_icon_position (f, icon_x, icon_y) + struct frame *f; int icon_x, icon_y; { - XWMHints wm_hints; - Window window = s->display.x->window_desc; + Window window = FRAME_X_WINDOW (f); - wm_hints.flags = IconPositionHint; - wm_hints.icon_x = icon_x; - wm_hints.icon_y = icon_y; - XSetWMHints (x_current_display, window, &wm_hints); + f->display.x->wm_hints.flags |= IconPositionHint; + f->display.x->wm_hints.icon_x = icon_x; + f->display.x->wm_hints.icon_y = icon_y; + + XSetWMHints (x_current_display, window, &f->display.x->wm_hints); } +/* Initialization. */ + void x_term_init (display_name) char *display_name; { - Lisp_Object screen; + Lisp_Object frame; char *defaultvalue; +#ifndef F_SETOWN_BUG #ifdef F_SETOWN extern int old_fcntl_owner; -#endif +#endif /* ! defined (F_SETOWN) */ +#endif /* F_SETOWN_BUG */ - x_focus_screen = x_highlight_screen = 0; + x_focus_frame = x_highlight_frame = 0; x_current_display = XOpenDisplay (display_name); if (x_current_display == 0) - fatal ("X server %s not responding; check the DISPLAY environment variable or use \"-d\"\n", + fatal ("X server %s not responding.\n\ +Check the DISPLAY environment variable or use \"-d\"\n", display_name); #ifdef HAVE_X11 { - int hostname_size = MAXHOSTNAMELEN + 1; + int hostname_size = 256; hostname = (char *) xmalloc (hostname_size); #if 0 XSetAfterFunction (x_current_display, x_trace_wire); -#endif - - invocation_name = Ffile_name_nondirectory (Fcar (Vcommand_line_args)); +#endif /* ! 0 */ /* Try to get the host name; if the buffer is too short, try again. Apparently, the only indication gethostname gives of @@ -3735,47 +4852,60 @@ x_term_init (display_name) hostname_size <<= 1; hostname = (char *) xrealloc (hostname, hostname_size); } - x_id_name = (char *) xmalloc (XSTRING (invocation_name)->size + x_id_name = (char *) xmalloc (XSTRING (Vinvocation_name)->size + strlen (hostname) + 2); - sprintf (x_id_name, "%s@%s", XSTRING (invocation_name)->data, hostname); + sprintf (x_id_name, "%s@%s", XSTRING (Vinvocation_name)->data, hostname); } - - dup2 (ConnectionNumber (x_current_display), 0); + + /* Figure out which modifier bits mean what. */ + x_find_modifier_meanings (); + + /* Get the scroll bar cursor. */ + x_vertical_scroll_bar_cursor + = XCreateFontCursor (x_current_display, XC_sb_v_double_arrow); + +#if 0 + /* Watch for PropertyNotify events on the root window; we use them + to figure out when to invalidate our cache of the cut buffers. */ + x_watch_cut_buffer_cache (); +#endif + + if (ConnectionNumber (x_current_display) != 0) + { + dup2 (ConnectionNumber (x_current_display), 0); #ifndef SYSV_STREAMS - /* Streams somehow keeps track of which descriptor number - is being used to talk to X. So it is not safe to substitute - descriptor 0. But it is safe to make descriptor 0 a copy of it. */ - close (ConnectionNumber (x_current_display)); - ConnectionNumber (x_current_display) = 0; /* Looks a little strange? + /* Streams somehow keeps track of which descriptor number + is being used to talk to X. So it is not safe to substitute + descriptor 0. But it is safe to make descriptor 0 a copy of it. */ + close (ConnectionNumber (x_current_display)); + ConnectionNumber (x_current_display) = 0; /* Looks a little strange? * check the def of the macro; * it is a genuine lvalue */ -#endif /* not SYSV_STREAMS */ +#endif /* SYSV_STREAMS */ + } -#endif /* HAVE_X11 */ +#endif /* ! defined (HAVE_X11) */ +#ifndef F_SETOWN_BUG #ifdef F_SETOWN old_fcntl_owner = fcntl (0, F_GETOWN, 0); #ifdef F_SETOWN_SOCK_NEG fcntl (0, F_SETOWN, -getpid ()); /* stdin is a socket here */ -#else +#else /* ! defined (F_SETOWN_SOCK_NEG) */ fcntl (0, F_SETOWN, getpid ()); -#endif /* F_SETOWN_SOCK_NEG */ -#endif /* F_SETOWN */ +#endif /* ! defined (F_SETOWN_SOCK_NEG) */ +#endif /* ! defined (F_SETOWN) */ +#endif /* F_SETOWN_BUG */ #ifdef SIGIO init_sigio (); -#endif - - /* Must use interrupt input because we cannot otherwise - arrange for C-g to be noticed immediately. - We cannot connect it to SIGINT. */ - Fset_input_mode (Qt, Qnil, Qt, Qnil); +#endif /* ! defined (SIGIO) */ expose_all_windows = 0; - clear_screen_hook = XTclear_screen; + clear_frame_hook = XTclear_frame; clear_end_of_line_hook = XTclear_end_of_line; ins_del_lines_hook = XTins_del_lines; change_line_highlight_hook = XTchange_line_highlight; @@ -3791,33 +4921,42 @@ x_term_init (display_name) read_socket_hook = XTread_socket; cursor_to_hook = XTcursor_to; reassert_line_highlight_hook = XTreassert_line_highlight; - screen_rehighlight_hook = XTscreen_rehighlight; mouse_position_hook = XTmouse_position; + frame_rehighlight_hook = XTframe_rehighlight; + frame_raise_lower_hook = XTframe_raise_lower; + set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar; + condemn_scroll_bars_hook = XTcondemn_scroll_bars; + redeem_scroll_bar_hook = XTredeem_scroll_bar; + judge_scroll_bars_hook = XTjudge_scroll_bars; - scroll_region_ok = 1; /* we'll scroll partial screens */ + scroll_region_ok = 1; /* we'll scroll partial frames */ char_ins_del_ok = 0; /* just as fast to write the line */ line_ins_del_ok = 1; /* we'll just blt 'em */ fast_clear_end_of_line = 1; /* X does this well */ - memory_below_screen = 0; /* we don't remember what scrolls + memory_below_frame = 0; /* we don't remember what scrolls off the bottom */ baud_rate = 19200; - XHandleError (x_error_handler); - XHandleIOError (x_error_handler); + /* Try to use interrupt input; if we can't, then start polling. */ + Fset_input_mode (Qt, Qnil, Qt, Qnil); + + /* Note that there is no real way portable across R3/R4 to get the + original error handler. */ + XHandleError (x_error_quitter); + XHandleIOError (x_io_error_quitter); /* Disable Window Change signals; they are handled by X events. */ #ifdef SIGWINCH signal (SIGWINCH, SIG_DFL); -#endif /* SIGWINCH */ +#endif /* ! defined (SIGWINCH) */ - signal (SIGPIPE, x_death_handler); + signal (SIGPIPE, x_connection_closed); } void syms_of_xterm () { - staticpro (&invocation_name); - invocation_name = Qnil; + staticpro (&last_mouse_scroll_bar); } -#endif /* HAVE_X11 */ -#endif /* HAVE_X_WINDOWS */ +#endif /* ! defined (HAVE_X11) */ +#endif /* ! defined (HAVE_X_WINDOWS) */