Mercurial > emacs
diff src/xterm.c @ 286:8a40ab4a424f
Initial revision
author | Jim Blandy <jimb@redhat.com> |
---|---|
date | Sat, 25 May 1991 06:46:10 +0000 |
parents | |
children | ac18f34e3e33 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/xterm.c Sat May 25 06:46:10 1991 +0000 @@ -0,0 +1,3798 @@ +/* X Communication module for terminals which understand the X protocol. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Serious problems: + + Kludge: dup2 is used to put the X-connection socket into desc # 0 + so that wait_reading_process_input will wait for it in place of + actual terminal input. + +*/ + +#include "config.h" + +#ifdef HAVE_X_WINDOWS + +#include "lisp.h" +#undef NULL + +/* On 4.3 this loses if it comes after xterm.h. */ +#include <signal.h> + +/* This may include sys/types.h, and that somehow loses + if this is not done before the other system files. */ +#include "xterm.h" + +/* Load sys/types.h if not already loaded. + In some systems loading it twice is suicidal. */ +#ifndef makedev +#include <sys/types.h> +#endif + +#ifdef BSD +#include <sys/ioctl.h> +#include <strings.h> +#else +#include <sys/termio.h> +#include <string.h> +#endif + +/* 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 + +#ifdef NEED_TIME_H +#include <time.h> +#else /* not NEED_TIME_H */ +#ifdef HAVE_TIMEVAL +#include <sys/time.h> +#endif /* HAVE_TIMEVAL */ +#endif /* not NEED_TIME_H */ + +#include <fcntl.h> +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <setjmp.h> +#include <sys/stat.h> +#include <sys/param.h> + +#include "dispextern.h" +#include "termhooks.h" +#include "termopts.h" +#include "termchar.h" +#if 0 +#include "sink.h" +#include "sinkmask.h" +#endif +#include "gnu.h" +#include "screen.h" +#include "disptab.h" +#include "window.h" +#include "buffer.h" +#include "xfns.h" + +#ifdef HAVE_X11 +#define XMapWindow XMapRaised /* Raise them when mapping. */ +#else +#include <X/Xkeyboard.h> +/*#include <X/Xproto.h> */ +#endif /* HAVE_X11 */ + +/* For sending Meta-characters. Do we need this? */ +#define METABIT 0200 + +#define min(a,b) ((a)<(b) ? (a) : (b)) +#define max(a,b) ((a)>(b) ? (a) : (b)) + +/* Nonzero means we must reprint all windows + because 1) we received an ExposeWindow event + or 2) we received too many ExposeRegion events to record. */ + +static int expose_all_windows; + +/* Nonzero means we must reprint all icon windows. */ + +static int expose_all_icons; + +#ifndef HAVE_X11 +/* ExposeRegion events, when received, are copied into this queue + for later processing. */ + +static struct event_queue x_expose_queue; + +/* ButtonPressed and ButtonReleased events, when received, + 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; + +#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; + +/* The id of a bitmap used for icon windows. + One such map is shared by all Emacs icon windows. + This is zero if we have not yet had a need to create the bitmap. */ + +static Bitmap icon_bitmap; + +/* Font used for text icons. */ + +static FONT_TYPE *icon_font_info; + +/* Stuff for dealing with the main icon title. */ + +extern Lisp_Object Vcommand_line_args; +char *hostname, *id_name, *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; + +/* From .Xdefaults, the value of "emacs.WarpMouse". If non-zero, + mouse is moved to inside of screen when screen is de-iconified. */ + +static int warp_mouse_on_deiconify; + +/* During an update, maximum vpos for ins/del line operations to affect. */ + +static int flexlines; + +/* During an update, nonzero if chars output now should be highlighted. */ + +static int highlight; + +/* Nominal cursor position -- where to draw output. + During an update, these are different from the cursor-box position. */ + +static int curs_x; +static int curs_y; + +#ifdef HAVE_X11 +/* `t' if a mouse button is depressed. */ + +extern Lisp_Object Vmouse_depressed; + +/* Tells if a window manager is present or not. */ + +extern Lisp_Object Vx_no_window_manager; + +/* Timestamp that we requested selection data was made. */ +extern Time requestor_time; + +/* ID of the window requesting selection data. */ +extern Window requestor_window; + +/* Nonzero enables some debugging for the X interface code. */ +extern int _Xdebug; + +#else /* X10 stuff */ + +/* Bit patterns for the mouse cursor. */ + +short MouseCursor[] = { + 0x0000, 0x0008, 0x0018, 0x0038, + 0x0078, 0x00f8, 0x01f8, 0x03f8, + 0x07f8, 0x00f8, 0x00d8, 0x0188, + 0x0180, 0x0300, 0x0300, 0x0000}; + +short MouseMask[] = { + 0x000c, 0x001c, 0x003c, 0x007c, + 0x00fc, 0x01fc, 0x03fc, 0x07fc, + 0x0ffc, 0x0ffc, 0x01fc, 0x03dc, + 0x03cc, 0x0780, 0x0780, 0x0300}; + +static short grey_bits[] = { + 0x0005, 0x000a, 0x0005, 0x000a}; + +static Pixmap GreyPixmap = 0; +#endif /* X10 stuff */ + +/* From time to time we get info on an Emacs window, here. */ + +static WINDOWINFO_TYPE windowinfo; + +extern int errno; + +extern Lisp_Object Vglobal_minibuffer_screen; + +extern Display *XOpenDisplay (); +extern Window XCreateWindow (); + +extern Cursor XCreateCursor (); +extern FONT_TYPE *XOpenFont (); + +static void flashback (); + +#ifndef HAVE_X11 +static void dumpqueue (); +#endif + +void dumpborder (); +static XTcursor_to (); +static 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 + should never be called except during an update, the only exceptions + being XTcursor_to, XTwrite_char and XTreassert_line_highlight. */ + +extern int mouse_track_top, mouse_track_left, mouse_track_width; + +static +XTupdate_begin (s) + struct screen *s; +{ + int mask; + + if (s == 0) + abort (); + + updating_screen = s; + flexlines = s->height; + highlight = 0; + +#if 0 + if (mouse_track_width != 0) + { + x_rectangle (s, s->display.x->reverse_gc, + mouse_track_top, mouse_track_left, mouse_track_width, 1); + mouse_track_width = 0; + } +#endif + BLOCK_INPUT; +#ifndef HAVE_X11 + dumpqueue (); +#endif + UNBLOCK_INPUT; +} + +static void x_do_pending_expose (); + +static +XTupdate_end (s) + struct screen *s; +{ + int mask; + + if (updating_screen == 0 + || updating_screen != s) + abort (); + + BLOCK_INPUT; +#ifndef HAVE_X11 + dumpqueue (); +#endif + adjust_scrollbars (s); + x_do_pending_expose (); + + x_display_cursor (s, 1); + + updating_screen = 0; + XFlushQueue (); + UNBLOCK_INPUT; +} + +/* External interface to control of standout mode. + Call this when about to modify line at position VPOS + and not change whether it is highlighted. */ + +XTreassert_line_highlight (new, vpos) + int new, vpos; +{ + highlight = new; +} + +/* Call this when about to modify line at position VPOS + and change whether it is highlighted. */ + +static +XTchange_line_highlight (new_highlight, vpos, first_unused_hpos) + int new_highlight, vpos, first_unused_hpos; +{ + highlight = new_highlight; + XTcursor_to (vpos, 0); + XTclear_end_of_line (updating_screen->width); +} + +/* This is used when starting Emacs and when restarting after suspend. + When starting Emacs, no X window is mapped. And nothing must be done + to Emacs's own window if it is suspended (though that rarely happens). */ + +static +XTset_terminal_modes () +{ +} + +/* This is called when exiting or suspending Emacs. + Exiting will make the X-windows go away, and suspending + requires no action. */ + +static +XTreset_terminal_modes () +{ +/* XTclear_screen (); */ +} + +/* Set the nominal cursor position of the screen: + where display update commands will take effect. + This does not affect the place where the cursor-box is displayed. */ + +XTcursor_to (row, col) + register int row, col; +{ + int mask; + int orow = row; + + curs_x = col; + curs_y = row; + + if (updating_screen == 0) + { + BLOCK_INPUT; + x_display_cursor (selected_screen, 1); + XFlushQueue (); + UNBLOCK_INPUT; + } +} + +/* Display a sequence of N glyphs found at GP. + WINDOW is the x-window to output to. LEFT and TOP are starting coords. + HL is 1 if this text is highlighted, 2 if the cursor is on it. + + 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; +{ + char buf[s->width]; + register char *cp = buf; + 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)); + + XDrawImageString16 (x_current_display, window, drawing_gc, + left, top + FONT_BASE (font), (XChar2b *) gp, n); +} + +#if 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; +{ + char buf[s->width]; /* Holds characters to be displayed. */ + 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; + + while (n) + { + /* 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; + + /* Find the run of consecutive glyphs with the same face-code. + Extract their character codes into BUF. */ + cp = buf; + while (n > 0) + { + g = *gp; + while (GLYPH_ALIAS_P (tbase, tlen, g)) + g = GLYPH_ALIAS (tbase, g); + if ((g >> 8) != cf) + break; + + *cp++ = 0377 & g; + --n; + ++gp; + } + + /* LEN gets the length of the run. */ + len = cp - buf; + + /* 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 + { +#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 */ + } + left += len * FONT_WIDTH (font); + } +} +#endif + +/* Output some text at the nominal screen cursor position, + advancing the cursor over the text. + Output LEN glyphs at START. + + `highlight', set up by XTreassert_line_highlight or XTchange_line_highlight, + controls the pixel values used for foreground and background. */ + +static +XTwrite_glyphs (start, len) + register GLYPH *start; + int len; +{ + register int temp_length; + int mask; + struct screen *s; + + BLOCK_INPUT; + + s = updating_screen; + if (s == 0) + { + s = selected_screen; + /* If not within an update, + output at the screen's visible cursor. */ + curs_x = s->cursor_x; + curs_y = s->cursor_y; + } + + /* Clear the cursor if it appears on this line. */ + if (curs_y == s->cursor_y) + x_display_cursor (s, 0); + + 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); + + if (updating_screen == 0) + { + s->cursor_x += len; + x_display_cursor (s, 1); + s->cursor_x -= len; + } + else + curs_x += len; + + UNBLOCK_INPUT; +} + +/* 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. */ + +static +XTclear_end_of_line (first_unused) + register int first_unused; +{ + struct screen *s = updating_screen; + int mask; + + if (s == 0) + abort (); + + if (curs_y < 0 || curs_y >= s->height) + return; + if (first_unused <= 0) + return; + + if (first_unused >= s->width) + first_unused = s->width; + + BLOCK_INPUT; + + /* Clear the cursor if it appears on this line. */ + if (curs_y == s->cursor_y) + x_display_cursor (s, 0); + +#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 */ + + UNBLOCK_INPUT; +} + +static +XTclear_screen () +{ + int mask; + struct screen *s = updating_screen; + + if (s == 0) + s = selected_screen; + + s->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); +#ifndef HAVE_X11 + dumpborder (s, 0); +#endif + XFlushQueue (); + UNBLOCK_INPUT; +} + +/* Paint horzontal bars down the screen for a visible bell. + Note that this may be way too slow on some machines. */ + +XTflash (s) + struct screen *s; +{ + register struct screen_glyphs *active_screen = SCREEN_CURRENT_GLYPHS (s); + register int i; + int x, y; + + if (updating_screen != 0) + abort (); + + 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 + + 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 */ + + XFlushQueue (); + UNBLOCK_INPUT; +} + +/* Flip background and forground colors of the screen. */ + +x_invert_screen (s) + struct screen *s; +{ +#ifdef HAVE_X11 + GC temp; + unsigned long pix_temp; + + 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; + + 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); + } + redraw_screen (s); +#endif /* X11 */ +} + +/* Make audible bell. */ + +#ifdef HAVE_X11 +#define XRINGBELL XBell(x_current_display, 0) +#else +#define XRINGBELL XFeep(0); +#endif + +XTring_bell () +{ + if (visible_bell) +#if 0 + XTflash (selected_screen); +#endif + { + x_invert_screen (selected_screen); + x_invert_screen (selected_screen); + } + else + { + BLOCK_INPUT; + XRINGBELL; + XFlushQueue (); + UNBLOCK_INPUT; + } +} + +/* Insert and delete character are not supposed to be used + because we are supposed to turn off the feature of using them. */ + +static +XTinsert_glyphs (start, len) + register char *start; + register int len; +{ + abort (); +} + +static +XTdelete_glyphs (n) + register int n; +{ + abort (); +} + +/* Specify how many text lines, from the top of the window, + should be affected by insert-lines and delete-lines operations. + This, and those operations, are used only within an update + that is bounded by calls to XTupdate_begin and XTupdate_end. */ + +static +XTset_terminal_window (n) + register int n; +{ + if (updating_screen == 0) + abort (); + + if ((n <= 0) || (n > updating_screen->height)) + flexlines = updating_screen->height; + else + flexlines = n; +} + +/* Perform an insert-lines operation, inserting N lines + at a vertical position curs_y. */ + +static void +stufflines (n) + register int n; +{ + register int topregion, bottomregion; + register int length, newtop, mask; + register struct screen *s = updating_screen; + int intborder = s->display.x->internal_border_width; + + if (curs_y >= flexlines) + return; + + topregion = curs_y; + bottomregion = flexlines - (n + 1); + newtop = topregion + n; + length = (bottomregion - topregion) + 1; + +#ifndef HAVE_X11 + dumpqueue (); +#endif + + 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)); + /* 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 */ + } + + newtop = min (newtop, (flexlines - 1)); + length = newtop - topregion; + 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, + 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 */ + } +} + +/* Perform a delete-lines operation, deleting N lines + at a vertical position curs_y. */ + +static void +scraplines (n) + register int n; +{ + int mask; + register struct screen *s = updating_screen; + int intborder = s->display.x->internal_border_width; + + if (curs_y >= flexlines) + return; + +#ifndef HAVE_X11 + dumpqueue (); +#endif + + 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 */ + } + } + else + { +#ifdef HAVE_X11 + XCopyArea (x_current_display, s->display.x->window_desc, + s->display.x->window_desc, s->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, + 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, + 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)); + /* 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 */ + } +} + +/* Perform an insert-lines or delete-lines operation, + inserting N lines or deleting -N lines at vertical position VPOS. */ + +XTins_del_lines (vpos, n) + int vpos, n; +{ + if (updating_screen == 0) + abort (); + + /* Clear the cursor. */ + x_display_cursor (updating_screen, 0); + + XTcursor_to (vpos, 0); + + BLOCK_INPUT; + if (n >= 0) + stufflines (n); + else + scraplines (-n); + XFlushQueue (); + UNBLOCK_INPUT; +} + +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. + 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; + register int left, top, cols, rows; +{ + register struct screen_glyphs *active_screen = SCREEN_CURRENT_GLYPHS (s); + int cursor_cleared = 0; + int bottom, right; + register int y; + + if (SCREEN_GARBAGED_P (s)) + 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 */ + + /* 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); + + /* 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; + + /* Get size in chars of the rectangle. */ + cols = right - left; + rows = bottom - top; + + /* If rectangle has zero area, return. */ + if (rows <= 0) return; + if (cols <= 0) return; + + /* 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)) + { + clear_cursor (s); + cursor_cleared = 1; + } + + /* Display the text in the rectangle, one text line at a time. */ + + for (y = top; y < bottom; y++) + { + GLYPH *line = &active_screen->glyphs[y][left]; + + if (! active_screen->enable[y] || left > active_screen->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); + } + + /* Turn the cursor on if we turned it off. */ + + if (cursor_cleared) + x_display_cursor (s, 1); + XFlushQueue (); +} + +#ifndef HAVE_X11 +/* Process all queued ExposeRegion events. */ + +static void +dumpqueue () +{ + register int i; + XExposeRegionEvent r; + + 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); + else + dumprectangle (s, r.x, r.y, r.width, r.height); + } + XFlushQueue (); +} +#endif + +/* 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. */ + +static void +x_do_pending_expose () +{ + int mask; + struct screen *s; + Lisp_Object tail, screen; + + if (expose_all_windows) + { + expose_all_windows = 0; + for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr) + { + register int temp_width, temp_height; + int intborder; + + screen = XCONS (tail)->car; + if (XTYPE (screen) != Lisp_Screen) + continue; + s = XSCREEN (screen); + if (s->output_method != output_x_window) + continue; + if (!s->visible) + continue; + if (!s->display.x->needs_exposure) + continue; + + intborder = s->display.x->internal_border_width; + + clear_cursor (s); + XGetWindowInfo (s->display.x->window_desc, &windowinfo); + temp_width = ((windowinfo.width - 2 * intborder + - s->display.x->v_scrollbar_width) + / FONT_WIDTH (s->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) + { + change_screen_size (s, max (1, temp_height), + max (1, temp_width), 0); + x_resize_scrollbars (s); + } + s->display.x->left_pos = windowinfo.x; + s->display.x->top_pos = windowinfo.y; + dumprectangle (s, 0, 0, PIXEL_WIDTH (s), PIXEL_HEIGHT (s)); +#if 0 + dumpborder (s, 0); +#endif + s->display.x->needs_exposure = 0; + if (updating_screen != s) + x_display_cursor (s, 1); + XFlushQueue (); + } + } + else + /* Handle any individual-rectangle expose events queued + for various windows. */ +#ifdef HAVE_X11 + ; +#else + dumpqueue (); +#endif +} + +#ifdef HAVE_X11 +static void +screen_highlight (screen) + struct screen *screen; +{ + 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); +} + +static void +screen_unhighlight (screen) + struct screen *screen; +{ + 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); +} +#else /* X10 */ +/* Dump the border-emphasis of screen S. + If S 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 ALWAYS is 0, don't bother explicitly drawing if it's background. + + ALWAYS = 1 is used when a screen 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; + int always; +{ + int thickness = s->display.x->internal_border_width / 2; + int width = PIXEL_WIDTH (s); + int height = PIXEL_HEIGHT (s); + int pixel; + + if (s != selected_screen) + { + if (!always) + return; + + pixel = s->display.x->background_pixel; + } + else + { + pixel = s->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, + thickness, pixel); + XPixSet (s->display.x->window_desc, width - thickness, 0, thickness, + height, pixel); + + if (always) + x_display_cursor (s, 1); +} +#endif /* X10 */ + +/* The focus has changed. Update the screens as necessary to reflect + the new situation. Note that we can't change the selected screen + here, because the lisp code we are interrupting might become confused. + For that, we enqueue a screen_selected event. + + Return the number of events stored at bufp. */ +static int +x_new_focus_screen (screen, bufp, buf_free) + struct screen *screen; + struct input_event *bufp; + int buf_free; +{ + struct screen *old_focus = x_focus_screen; + int events_enqueued = 0; + + if (screen == x_focus_screen) + return 0; + + /* Set this before calling screen_{un,}highlight, so that they see + the correct value of x_focus_screen. */ + x_focus_screen = screen; + + if (old_focus) + { + if (old_focus->auto_lower) + x_lower_screen (old_focus); + screen_unhighlight (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) + { + if (x_focus_screen->auto_raise) + x_raise_screen (x_focus_screen); + screen_highlight (x_focus_screen); + + /* Enqueue an event. It's kind of important not to drop these + events, but the event queue's fixed size is a real pain in the butt + anyway. */ + if (buf_free > 0) + { + bufp->kind = screen_selected; + bufp->screen = screen; + events_enqueued++; + } + } + + return events_enqueued; +} + +enum window_type +{ + no_window, + scrollbar_window, + text_window, +}; + +/* Symbol returned in input stream to indicate mouse movement. */ +Lisp_Object Qmouse_moved; + +/* Position of the mouse in characters */ +unsigned int x_mouse_x, x_mouse_y; + +/* Emacs window the mouse is in, if any. */ +extern Lisp_Object Vmouse_window; + +/* Offset in buffer of character under the pointer, or 0. */ +extern int mouse_buffer_offset; + +/* Part of the screen the mouse is in. */ +extern Lisp_Object Vmouse_screen_part; + +extern void pixel_to_glyph_translation (); +extern int buffer_posn_from_coords (); + +/* 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. */ + +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; +{ + 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; + + 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; +#endif + + pixel_to_glyph_translation (s, pix_x, pix_y, &x, &y); + if (x == x_mouse_x && y == x_mouse_y) + return; + + x_mouse_x = x; + x_mouse_y = y; + + /* What sort of window are we in now? */ + if (window_type == text_window) /* Text part */ + { + int modeline_p; + + Vmouse_window = window_from_coordinates (s, x, y, &modeline_p); + + if (XTYPE (Vmouse_window) == Lisp_Window) + mouse_buffer_offset + = buffer_posn_from_coords (XWINDOW (Vmouse_window), x, y); + else + mouse_buffer_offset = 0; + + 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; + + return; + } + else if (window_type == scrollbar_window) /* Scrollbar */ + { + Vmouse_window = s->selected_window; + mouse_buffer_offset = 0; + Vmouse_screen_part = part; + + result->kind = window_sys_event; + result->code = Qmouse_moved; + + return; + } + + return; +} +#endif + +/* Given a pixel position (pix_x, pix_y) on the screen s, return + character co-ordinates in (*x, *y). */ +void +pixel_to_glyph_translation (s, pix_x, pix_y, x, y) + SCREEN_PTR s; + register unsigned int pix_x, pix_y; + register int *x, *y; +{ + register struct screen_glyphs *s_glyphs = SCREEN_CURRENT_GLYPHS (s); + register int line = SCREEN_HEIGHT (s) - 1; + int ibw = s->display.x->internal_border_width; + + /* What line is it on? */ + line = SCREEN_HEIGHT (s) - 1; + while (s_glyphs->top_left_y[line] > pix_y) + line--; + *y = line; + + /* Horizontally, is it in the border? */ + if (pix_x < ibw) + *x = 0; + + /* If it's off the right edge, clip it. */ + else if (pix_x > s->display.x->pixel_width - ibw) + *x = SCREEN_WIDTH (s) - 1; + + /* It's in the midst of the screen; assume all the characters are + the same width, and figure the column. */ + else + *x = (pix_x - ibw) / FONT_WIDTH (s->display.x->font); +} + +#ifdef HAVE_X11 + +/* Any buttons grabbed. */ +unsigned int x_mouse_grabbed; + +/* Convert a set of X modifier bits to the proper form for a + struct input_event modifiers value. */ + +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)); +} + +extern struct screen *x_window_to_scrollbar (); +extern Lisp_Object Vmouse_event; + +/* 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. */ + +static Lisp_Object +construct_mouse_click (result, event, s, part, prefix) + struct input_event *result; + XButtonEvent *event; + struct screen *s; + int prefix; + Lisp_Object part; +{ + /* Initialize those fields text and scrollbar clicks hold in common. + 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->modifiers = (x_convert_modifiers (event->state) + | (event->type == ButtonRelease ? up_modifier : 0)); + XSET (result->timestamp, Lisp_Int, (event->time & 0x7fffff)); + + /* Notice if the mouse is still grabbed. */ + if (event->type == ButtonPress) + { + if (! x_mouse_grabbed) + Vmouse_depressed = Qt; + x_mouse_grabbed |= event->button; + } + else if (event->type == ButtonRelease) + { + x_mouse_grabbed &= ~(event->button); + if (!x_mouse_grabbed) + 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; + + pixel_to_glyph_translation (s, + event->x, event->y, + &column, &row); + + result->kind = mouse_click; + result->x = column; + result->y = row; + result->screen = s; + } +} + + +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 */ + +/* Symbols returned in the input stream to indicate various X events. */ +Lisp_Object Qmapped_screen; +Lisp_Object Qunmapped_screen; +Lisp_Object Qexited_scrollbar; +Lisp_Object Qexited_window; +Lisp_Object Qredraw_screen; +Lisp_Object Qmouse_click; +Lisp_Object Qscrollbar_click; + +/* 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; + +/* 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. + + Events representing keys are stored in buffer BUFP, + which can hold up to NUMCHARS characters. + We return the number of characters stored into the buffer, + thus pretending to be `read'. + + WAITP is nonzero if we should block until input arrives. + EXPECTED is nonzero if the caller knows input is available. */ + +Lisp_Object +XTread_socket (sd, bufp, numchars, waitp, expected) + register int sd; + register struct input_event *bufp; + register int numchars; + int waitp; + int expected; +{ + int count = 0; + int nbytes = 0; + int mask; + int items_pending; /* How many items are in the X queue. */ + XEvent event; + struct screen *s; + int event_found; + int prefix; + Lisp_Object part; + + if (x_input_blocked) + { + x_pending_input = 1; + return -1; + } + + x_pending_input = 0; + BLOCK_INPUT; + + if (numchars <= 0) + abort (); /* Don't think this happens. */ + +#ifdef FIOSNBIO + /* If available, Xlib uses FIOSNBIO to make the socket + non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set, + 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 + +#ifndef SIGIO +#ifndef HAVE_SELECT + if (! (fcntl (fileno (stdin), F_GETFL, 0) & O_NDELAY)) + { + extern int read_alarm_should_throw; + read_alarm_should_throw = 1; + XPeekEvent (XDISPLAY &event); + read_alarm_should_throw = 0; + } +#endif +#endif + + while (XStuffPending () != 0) + { + XNextEvent (XDISPLAY &event); + event_found = 1; + + switch (event.type) + { +#ifdef HAVE_X11 + + case SelectionClear: /* Someone has grabbed ownership. */ + x_disown_selection (event.xselectionclear.window, + event.xselectionclear.selection, + event.xselectionclear.time); + break; + + case SelectionRequest: /* Someone wants our selection. */ + x_answer_selection_request (event); + break; + + case PropertyNotify: + /* If we were to do this synchronously, there'd be no worry + about re-selecting. */ + x_send_incremental (event); + break; + + case Expose: + s = x_window_to_screen (event.xexpose.window); + if (s) + { + if (s->visible == 0) + { + s->visible = 1; + s->iconified = 0; + SET_SCREEN_GARBAGED (s); + } + else + dumprectangle (x_window_to_screen (event.xexpose.window), + event.xexpose.x, event.xexpose.y, + event.xexpose.width, event.xexpose.height); + } + 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); + break; + + case NoExpose: /* This occurs when an XCopyArea's + source area was completely + available */ + break; +#else /* not 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) + { + refreshicon (s); + s->iconified = 1; + } + if (event.window == s->display.x->window_desc) + { + /* Say must check all windows' needs_exposure flags. */ + expose_all_windows = 1; + s->display.x->needs_exposure = 1; + s->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) + { + refreshicon (s); + break; + } + /* If window already needs full redraw, ignore this rectangle. */ + if (expose_all_windows && s->display.x->needs_exposure) + break; + /* Put the event on the queue of rectangles to redraw. */ + if (enqueue_event (&event, &x_expose_queue)) + /* If it is full, we can't record the rectangle, + so redraw this entire window. */ + { + /* Say must check all windows' needs_exposure flags. */ + expose_all_windows = 1; + s->display.x->needs_exposure = 1; + } + break; + + case ExposeCopy: + /* This should happen only when we are expecting it, + in x_read_exposes. */ + abort (); +#endif /* not 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; + Vmouse_window = Vmouse_screen_part = Qnil; + x_mouse_x = x_mouse_y = -1; + } + } + break; + + case MapNotify: + s = x_window_to_screen (event.xmap.window); + if (s) + { + s->visible = 1; + s->iconified = 0; + + /* wait_reading_process_input will notice this and update + the screen's display structures. */ + SET_SCREEN_GARBAGED (s); + } + break; + + /* Turn off processing if we become fully obscured. */ + case VisibilityNotify: + break; + +#else + 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; + break; +#endif /* HAVE_X11 */ + +#ifdef HAVE_X11 + case KeyPress: + s = x_window_to_screen (event.xkey.window); + if (s != 0) + { + KeySym keysym; + XComposeStatus status; + char copy_buffer[80]; + + /* This will have to go some day... */ + nbytes = XLookupString (&event.xkey, + copy_buffer, + 80, + &keysym, + &status); + + if (numchars > 1) + { + if (IsCursorKey (keysym) /* >= 0xff50 < 0xff60 */ + || IsMiscFunctionKey (keysym) /* >= 0xff60 < 0xff80 */ + || IsKeypadKey (keysym) /* >= 0xff80 <= 0xffbd */ + || IsFunctionKey (keysym)) /* >= 0xffbe <= 0xffe0 */ + { + bufp->kind = non_ascii_keystroke; + bufp->code = (unsigned) keysym - 0xff50; + bufp->modifiers = x_convert_modifiers (event.xkey.state); + bufp++; + count++; + numchars--; + } + else if (numchars > nbytes) + { + register int i; + + if (nbytes == 1) + { + if (event.xkey.state & Mod1Mask) + *copy_buffer |= METABIT; + bufp->kind = ascii_keystroke; + XSET (bufp->code, Lisp_Int, *copy_buffer); + bufp++; + } + else + for (i = nbytes - 1; i > 1; i--) + { + bufp->kind = ascii_keystroke; + XSET (bufp->code, Lisp_Int, copy_buffer[i]); + bufp++; + } + + count += nbytes; + numchars -= nbytes; + } + } + } + break; +#else + case KeyPressed: + { + register char *where_mapping; + + s = x_window_to_screen (event.window); + /* Ignore keys typed on icon windows. */ + if (s != 0 && event.window == s->display.x->icon_desc) + break; + where_mapping = XLookupMapping (&event, &nbytes); + /* Nasty fix for arrow keys */ + if (!nbytes && IsCursorKey (event.detail & 0xff)) + { + switch (event.detail & 0xff) + { + case KC_CURSOR_LEFT: + where_mapping = "\002"; + break; + case KC_CURSOR_RIGHT: + where_mapping = "\006"; + break; + case KC_CURSOR_UP: + where_mapping = "\020"; + break; + case KC_CURSOR_DOWN: + where_mapping = "\016"; + break; + } + nbytes = 1; + } + if (numchars - nbytes > 0) + { + register int i; + + for (i = 0; i < nbytes; i++) + { + bufp->kind = ascii_keystroke; + XSET (bufp->code, Lisp_Int, where_mapping[i]); + bufp++; + } + count += nbytes; + numchars -= nbytes; + } + } + break; +#endif /* HAVE_X11 */ + +#ifdef HAVE_X11 + case EnterNotify: + if (event.xcrossing.detail == NotifyInferior) /* Left Scrollbar */ + ; + else 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; + + s = x_window_to_screen (event.xcrossing.window); + + /* Avoid nasty pop/raise loops. */ + if (s && (!(s->auto_raise) + || !(s->auto_lower) + || (event.xcrossing.time - enter_timestamp) > 500)) + { + int n = x_new_focus_screen (s, bufp, numchars); + bufp += n; + numchars -= n; + 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 + } +#if 0 + else if (s = x_window_to_screen (event.xcrossing.window)) + x_mouse_screen = s; +#endif + + break; + + case FocusIn: + s = x_window_to_screen (event.xfocus.window); + if (s) + { + int n = x_new_focus_screen (s, bufp, numchars); + bufp += n; + numchars -= n; + } + break; + + case LeaveNotify: + if (event.xcrossing.detail != NotifyInferior + && event.xcrossing.subwindow == None + && event.xcrossing.mode == NotifyNormal) + { + if (event.xcrossing.focus + && (x_focus_screen + == x_window_to_screen (event.xcrossing.window))) + { + int n = x_new_focus_screen (0, bufp, numchars); + bufp += n; + numchars -= n; + } + } + break; + + case FocusOut: + s = x_window_to_screen (event.xfocus.window); + if (s && s == x_focus_screen) + { + int n = x_new_focus_screen (0, bufp, numchars); + bufp += n; + numchars -= n; + } + break; + +#else /* not HAVE_X11 */ + + case EnterWindow: + if ((event.detail & 0xFF) == 1) + break; /* Coming from our own subwindow */ + if (event.subwindow != 0) + break; /* Entering our own subwindow. */ + + { + extern int waiting_for_input; + struct screen *old_s = x_input_screen; + + s = x_window_to_screen (event.window); + x_mouse_screen = s; + + if (waiting_for_input && x_focus_screen == 0) + x_new_selected_screen (s); + } + break; + + case LeaveWindow: + if ((event.detail & 0xFF) == 1) + break; /* Entering our own subwindow */ + 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) + { + s = x_input_screen; + x_input_screen = 0; + if (s) + screen_unhighlight (s); + } + break; +#endif /* not HAVE_X11 */ + +#ifdef HAVE_X11 + case MotionNotify: + { + s = x_window_to_screen (event.xmotion.window); + if (s) + { + int row, column; + + pixel_to_glyph_translation (s, + event.xmotion.x, event.xmotion.y, + &column, &row); + + note_mouse_position (s, column, row, event.xmotion.time); + } +#if 0 + else if ((s = x_window_to_scrollbar (event.xmotion.window, + &part, &prefix))) + { + What should go here? + } +#endif + } + break; + + case ConfigureNotify: + { + int rows, columns; + s = x_window_to_screen (event.xconfigure.window); + if (!s) + break; + + 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)); + + if (columns != s->width || rows != s->height) + { + XEvent ignored_event; + + change_screen_size (s, rows, columns, 0); + x_resize_scrollbars (s); + SET_SCREEN_GARBAGED (s); +#if 0 + dumprectangle (s, 0, 0, PIXEL_WIDTH (s), PIXEL_HEIGHT (s)); + /* Throw away the exposures generated by this reconfigure. */ + while (XCheckWindowEvent (x_current_display, + event.xconfigure.window, + ExposureMask, &ignored_event) + == True); +#endif + } + + s->display.x->left_pos = event.xconfigure.x; + s->display.x->top_pos = event.xconfigure.y; + s->display.x->pixel_width = event.xconfigure.width; + s->display.x->pixel_height = event.xconfigure.height; + break; + } + + case ButtonPress: + case ButtonRelease: + { + /* 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; + + 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; + 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; + } + + if (numchars >= 1 && emacs_event.kind != no_event) + { + bcopy (&emacs_event, bufp, sizeof (struct input_event)); + bufp++; + count++; + numchars--; + } + } + break; + +#else /* not HAVE_X11 */ + case ButtonPressed: + case ButtonReleased: + s = x_window_to_screen (event.window); + if (s) + { + if (event.window == s->display.x->icon_desc) + { + x_make_screen_visible (s); + + if (warp_mouse_on_deiconify) + XWarpMouse (s->display.x->window_desc, 10, 10); + break; + } + if (event.window == s->display.x->window_desc) + { + if (s->auto_raise) + x_raise_screen (s); + } + } + enqueue_event (&event, &x_mouse_queue); + if (numchars >= 2) + { + bufp->kind = ascii_keystroke; + bufp->code = (char) 'X' & 037; /* C-x */ + bufp++; + + bufp->kind = ascii_keystroke; + bufp->code = (char) 0; /* C-@ */ + bufp++; + + count += 2; + numchars -= 2; + } + break; +#endif /* not HAVE_X11 */ + +#ifdef HAVE_X11 + + case CirculateNotify: + break; + case CirculateRequest: + break; + +#endif /* HAVE_X11 */ + + case MappingNotify: + if (event.xmapping.request == MappingKeyboard) + /* Someone has changed the keyboard mapping - flush the + local cache. */ + XRefreshKeyboardMapping (&event.xmapping); + break; + + default: + break; + } + } + +#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; + + if (0 != select (fd + 1, &mask, (long *) 0, (long *) 0, + (struct timeval *) 0) + && !XStuffPending ()) + kill (getpid (), SIGHUP); + } +#endif /* HAVE_SELECT */ +#endif + + if (updating_screen == 0) + x_do_pending_expose (); + + UNBLOCK_INPUT; + return count; +} + +#ifndef HAVE_X11 +/* Read and process only Expose events + until we get an ExposeCopy event; then return. + This is used in insert/delete line. + We assume input is already blocked. */ + +static void +x_read_exposes () +{ + struct screen *s; + XKeyPressedEvent event; + + while (1) + { + /* while there are more events*/ + XMaskEvent (ExposeWindow | ExposeRegion | ExposeCopy, &event); + switch (event.type) + { + case ExposeWindow: + if (event.subwindow != 0) + break; /* duplicate event */ + s = x_window_to_screen (event.window); + if (event.window == s->display.x->icon_desc) + { + refreshicon (s); + break; + } + if (event.window == s->display.x->window_desc) + { + expose_all_windows = 1; + s->display.x->needs_exposure = 1; + break; + } + 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) + { + refreshicon (s); + break; + } + /* If window already needs full redraw, ignore this rectangle. */ + if (expose_all_windows && s->display.x->needs_exposure) + break; + /* Put the event on the queue of rectangles to redraw. */ + if (enqueue_event (&event, &x_expose_queue)) + /* If it is full, we can't record the rectangle, + so redraw this entire window. */ + { + /* Say must check all windows' needs_exposure flags. */ + expose_all_windows = 1; + s->display.x->needs_exposure = 1; + } + break; + + case ExposeCopy: + return; + } + } +} +#endif /* HAVE_X11 */ + +static int +XTmouse_tracking_enable (enable) + int enable; +{ + Lisp_Object tail; + + /* Go through the list of screens and turn on/off mouse tracking for + each of them. */ + for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr) + { + if (XTYPE (XCONS (tail)->car) != Lisp_Screen) + abort (); + if (XSCREEN (XCONS (tail)->car)->output_method == output_x_window) + XSelectInput (x_current_display, + XSCREEN (XCONS (tail)->car)->display.x->window_desc, + (enable + ? (STANDARD_EVENT_SET + | PointerMotionMask + | ButtonReleaseMask) + : STANDARD_EVENT_SET)); + } +} + + +static Lisp_Object +XTmouse_position () +{ + +} + + + +/* Draw a hollow box cursor. Don't change the inside of the box. */ + +static void +x_draw_box (s) + struct screen *s; +{ + 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); + +#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, + left, top, width - 1, height - 1); +#else + XPixSet (s->display.x->window_desc, + left, top, width, 1, + s->display.x->cursor_pixel); + + XPixSet (s->display.x->window_desc, + left, top, 1, height, + s->display.x->cursor_pixel); + + XPixSet (s->display.x->window_desc, + left+width-1, top, 1, height, + s->display.x->cursor_pixel); + + XPixSet (s->display.x->window_desc, + left, top+height-1, width, 1, + s->display.x->cursor_pixel); +#endif /* HAVE_X11 */ +} + +/* Clear the cursor of screen S 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; +{ + int mask; + + if (! s->visible + || s->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_bar_cursor (s, on) + struct screen *s; + 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; + + if (! s->visible || (! on && s->phys_cursor_x < 0)) + 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; + + XDrawLine (x_current_display, s->display.x->window_desc, + s->display.x->reverse_gc, x1, y1, x1, y2); + + s->phys_cursor_x = phys_x = -1; + } + + if (on && s == x_focus_screen) + { + 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; + + XDrawLine (x_current_display, s->display.x->window_desc, + s->display.x->cursor_gc, x1, y1, x1, y2); + + s->phys_cursor_x = s->cursor_x; + s->phys_cursor_y = s->cursor_y; + } +#else /* X10 */ + Give it up, dude. +#endif /* X10 */ +} + + +/* Redraw the glyph at ROW, COLUMN on screen S, in the style HIGHLIGHT. + If there is no character there, erase the area. HIGHLIGHT is as + defined for dumpglyphs. */ + +static void +x_draw_single_glyph (s, row, column, highlight) + struct screen *s; + int row, column; + int highlight; +{ + register struct screen_glyphs *current_screen = SCREEN_CURRENT_GLYPHS (s); + + /* If there is supposed to be a character there, redraw it + in that line's normal video. */ + if (current_screen->enable[row] + && column < current_screen->used[row]) + 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), + ¤t_screen->glyphs[row][column], + 1, highlight, s->display.x->font); + else + { +#ifdef HAVE_X11 + static GLYPH a_space_glyph = SPACEGLYPH; + 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), + &a_space_glyph, 1, highlight, s->display.x->font); +#else + XPixSet (s->display.x->window_desc, + (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), + FONT_WIDTH (s->display.x->font), + FONT_HEIGHT (s->display.x->font), + (highlight == 0 + ? s->display.x->background_pixel + : (highlight == 1 + ? s->display.x->foreground_pixel + : s->display.x->cursor_pixel))); +#endif /* HAVE_X11 */ + } +} + +/* Turn the displayed cursor of screen S 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. */ + +static void +x_display_box_cursor (s, on) + struct screen *s; + int on; +{ + if (! s->visible) + return; + + /* If cursor is off and we want it off, return quickly. */ + + if (!on && s->phys_cursor_x < 0) + return; + + /* 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 + && (!on + || s->phys_cursor_x != s->cursor_x + || s->phys_cursor_y != s->cursor_y + || (s->display.x->text_cursor_kind != hollow_box_cursor + && (s != x_focus_screen)))) + { + /* Erase the cursor by redrawing the character underneath it. */ + x_draw_single_glyph (s, s->phys_cursor_y, s->phys_cursor_x, + (SCREEN_CURRENT_GLYPHS (s) + ->highlight[s->phys_cursor_y])); + + s->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_focus_screen))) + { + if (s != x_focus_screen) + { + x_draw_box (s); + s->display.x->text_cursor_kind = hollow_box_cursor; + } + else + { + x_draw_single_glyph (s, s->cursor_y, s->cursor_x, 2); + s->display.x->text_cursor_kind = filled_box_cursor; + } + + s->phys_cursor_x = s->cursor_x; + s->phys_cursor_y = s->cursor_y; + } + + if (updating_screen != s) + XFlushQueue (); +} + +#if 0 +This code has been rewritten to use x_draw_single_glyph and draw +box cursors successfully. Once that code is working, this can go away. + +/* Turn the displayed cursor of screen S 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. */ + +static void +x_display_box_cursor (s, on) + struct screen *s; + int on; +{ + register struct screen_glyphs *current_screen = SCREEN_CURRENT_GLYPHS (s); + + if (! s->visible) + return; + + /* If cursor is off and we want it off, return quickly. */ + + if (!on && s->phys_cursor_x < 0) + return; + + /* If cursor is currently being shown and we don't want it to be + or it is in the wrong place, erase it. */ + + if (s->phys_cursor_x >= 0 + && (!on || s->phys_cursor_x != s->cursor_x + || s->phys_cursor_y != s->cursor_y)) + { + /* If there is supposed to be a character there, redraw it + in that line's normal video. */ + if (current_screen->enable[s->phys_cursor_y] + && s->phys_cursor_x < current_screen->used[s->phys_cursor_y]) + dumpglyphs (s, + (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), + ¤t_screen->glyphs[s->phys_cursor_y][s->phys_cursor_x], + 1, current_screen->highlight[s->phys_cursor_y], + s->display.x->font); + /* Otherwise just erase the space. */ + else +#ifdef HAVE_X11 + 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), + FONT_HEIGHT (s->display.x->font), False); +#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; + } + + /* If we want to show a cursor, write it in the right place. */ + + if (on && s->phys_cursor_x < 0) + { + if (s != selected_screen || s != x_input_screen) + x_draw_box (s); + else if (current_screen->enable[s->cursor_y] + && s->cursor_x < current_screen->used[s->cursor_y]) + /* There is a character there: draw the character with + cursor coloration. */ + dumpglyphs (s, + (s->cursor_x * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width), + (s->cursor_y * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width), + ¤t_screen->glyphs[s->cursor_y][s->cursor_x], + 1, 2, s->display.x->font); + else +#ifdef HAVE_X11 + { + GLYPH space = SPACEGLYPH; + dumpglyphs (s, + (s->cursor_x * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width), + (s->cursor_y * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width), + &space, 1, + 2, s->display.x->font); + } +#if 0 + /* This kills the HP-BSD X11R3 server... */ + XFillRectangle (x_current_display, s->display.x->window_desc, + s->display.x->cursor_gc, + s->cursor_x * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width, + s->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)); +#endif +#else + XPixSet (s->display.x->window_desc, + s->cursor_x * FONT_WIDTH (s->display.x->font)+s->display.x->internal_border_width, + s->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->cursor_pixel); +#endif /* HAVE_X11 */ + + s->phys_cursor_x = s->cursor_x; + s->phys_cursor_y = s->cursor_y; + } + + if (updating_screen != s) + XFlushQueue (); +} +#endif + +extern Lisp_Object Vbar_cursor; + +x_display_cursor (s, on) + struct screen *s; + int on; +{ + if (EQ (Vbar_cursor, Qnil)) + x_display_box_cursor (s, on); + else + x_display_bar_cursor (s, on); +} + +/* Icons. */ + +/* Refresh bitmap kitchen sink icon for screen S + when we get an expose event for it. */ + +refreshicon (s) + struct screen *s; +{ +#ifdef HAVE_X11 + /* Normally, the window manager handles this function. */ +#else + int mask; + + if (s->display.x->icon_bitmap_flag) + XBitmapBitsPut (s->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; + struct Lisp_String *str; + unsigned char *string; + + string + = XSTRING (XBUFFER (XWINDOW (s->selected_window)->buffer)->name)->data; + + if (s->display.x->icon_label != string) + { + s->display.x->icon_label = string; + XChangeWindow (s->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, + str->size, icon_font_info->id, + BLACK_PIX_DEFAULT, WHITE_PIX_DEFAULT); + } + XFlushQueue (); +#endif /* HAVE_X11 */ +} + +/* Make the x-window of screen S use the kitchen-sink icon + that's a window generated by Emacs. */ + +int +x_bitmap_icon (s) + struct screen *s; +{ + int mask; + Window icon_window; + + if (s->display.x->window_desc == 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) + { + XClearIconWindow (s->display.x->window_desc); + XDestroyWindow (s->display.x->icon_desc); + } + + icon_window = XCreateWindow (s->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); + XSelectInput (icon_window, ExposeWindow | UnmapWindow); + + s->display.x->icon_desc = icon_window; + s->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 */ + + return 0; +} + + +/* Make the x-window of screen S use a rectangle with text. */ + +int +x_text_icon (s, icon_name) + struct screen *s; + char *icon_name; +{ +#ifndef HAVE_X11 + int mask; + int width; + Window icon_window; + char *X_DefaultValue; + Bitmap b1; + +#if 0 /* This doesn't seem to be used, but I can't quite believe it. */ + static Pixmap grey_pixmap; +#endif + +#ifndef WhitePixel +#define WhitePixel 1 +#endif + +#ifndef BlackPixel +#define BlackPixel 0 +#endif +#endif /* not HAVE_X11 */ + + if (s->display.x->window_desc == 0) + return 1; + + if (icon_font_info == 0) + icon_font_info + = XGetFont (XGetDefault (XDISPLAY invocation_name, "BodyFont")); + +#ifdef HAVE_X11 + if (icon_name) + s->display.x->icon_label = icon_name; + else + if (! s->display.x->icon_label) + s->display.x->icon_label = " *emacs* "; + + XSetIconName (x_current_display, s->display.x->window_desc, + (char *) s->display.x->icon_label); + + s->display.x->icon_bitmap_flag = 0; +#else + if (s->display.x->icon_desc) + { + XClearIconWindow (XDISPLAY s->display.x->window_desc); + XDestroyWindow (XDISPLAY s->display.x->icon_desc); + } + + if (icon_name) + s->display.x->icon_label = (unsigned char *) icon_name; + else + if (! s->display.x->icon_label) + s->display.x->icon_label = XSTRING (s->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 + 10, icon_font_info->height + 10, + 2, BlackPixmap, WhitePixmap); + + if (icon_window == 0) + return 1; + + XSetIconWindow (s->display.x->window_desc, 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 */ + + return 0; +} + +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) + +x_handle_error_gracefully (event) + XErrorEvent *event; +{ + char error_ptr[128]; + char *proto_ptr = x_proto_requests[event->request_code]; + char str[128]; + + 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); +} + +#if 0 +extern int x_selection_alloc_error; +extern int x_converting_selection; +#endif + +/* Handle X Errors. If the error is not traumatic, + just call error (). Otherwise print a (hopefully) interesting + message and quit. + + The arg to Fkill_emacs is an exit status value + and also prevents any questions. */ + +x_error_handler (disp, event) + Display *disp; +#ifdef HAVE_X11 + XErrorEvent *event; + +#define XlibDisplayIOError (1L << 0) + +#else + struct _XErrorEvent *event; +#endif +{ + /* Here we use the standard X handlers. */ + + 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 + { + disp->flags |= XlibDisplayIOError; + _XDefaultIOError (disp); + } + UNBLOCK_INPUT; + + if (_Xdebug) + abort (); + else + Fkill_emacs (make_number (70)); +} + +/* Initialize communication with the X window server. */ + +#if 0 +static unsigned int x_wire_count; +x_trace_wire () +{ + fprintf (stderr, "Lib call: %d\n", ++x_wire_count); +} +#endif + + +/* Set the font of the x-window specified by screen S + to the font named NEWNAME. This is safe to use + even before S has an actual x-window. */ + +#ifdef HAVE_X11 + +/* A table of all the fonts we have already loaded. */ +static XFontStruct **x_font_table; + +/* The current capacity of x_font_table. */ +static int x_font_table_size; + +/* The number of fonts actually stored in x_font_table. + x_font_table[n] is used and valid iff 0 <= n < n_fonts. + 0 <= n_fonts <= x_font_table_size. */ +static int n_fonts; + +x_new_font (s, fontname) + struct screen *s; + register char *fontname; +{ + XFontStruct *temp; + int already_loaded; + int n_matching_fonts; + XFontStruct *font_info; + char **font_names; + + /* 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; + + /* See if we've already loaded this font. */ + { + 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; + } + } + found_font: + + /* If we have, just return it from the table. */ + if (already_loaded) + { + s->display.x->font = x_font_table[already_loaded]; + } + + /* Otherwise, load the font and add it to the table. */ + else + { + XFontStruct *font; + + font = (XFontStruct *) XLoadQueryFont (x_current_display, fontname); + if (! font) + return 1; + + /* 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])); + } + /* Do we need to grow the table? */ + else if (n_fonts >= x_font_table_size) + { + x_font_table_size <<= 1; + x_font_table + = (XFontStruct **) xrealloc (x_font_table, + (x_font_table_size + * sizeof (x_font_table[0]))); + } + + s->display.x->font = x_font_table[n_fonts++] = 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) + { + 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); + } + + return 0; +} +#else +x_new_font (s, newname) + struct screen *s; + register char *newname; +{ + FONT_TYPE *temp; + int mask; + + temp = XGetFont (newname); + if (temp == (FONT_TYPE *) 0) + return 1; + + if (s->display.x->font) + XLoseFont (s->display.x->font); + + s->display.x->font = temp; + + if (s->display.x->window_desc != 0) + x_set_window_size (s, s->width, s->height); + + return 0; +} +#endif + +x_calc_absolute_position (s) + struct screen *s; +{ +#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 */ + WINDOWINFO_TYPE parentinfo; + + XGetWindowInfo (s->display.x->window_desc, &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 (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 */ +} + +x_set_offset (s, xoff, yoff) + struct screen *s; + register int xoff, yoff; +{ + s->display.x->top_pos = yoff; + s->display.x->left_pos = xoff; + x_calc_absolute_position (s); + + BLOCK_INPUT; + XMoveWindow (XDISPLAY s->display.x->window_desc, + s->display.x->left_pos, s->display.x->top_pos); +#ifdef HAVE_X11 + x_wm_set_size_hint (s, 0); +#endif + UNBLOCK_INPUT; +} + +/* Call this to change the size of screen S's x-window. */ + +x_set_window_size (s, cols, rows) + struct screen *s; + register 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); + +#ifdef HAVE_X11 + x_wm_set_size_hint (s, 0); +#endif /* HAVE_X11 */ + XChangeWindowSize (s->display.x->window_desc, pixelwidth, pixelheight); + XFlushQueue (); + UNBLOCK_INPUT; +} + +#ifndef HAVE_X11 +x_set_resize_hint (s) + struct screen *s; +{ + + 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)); +} +#endif /* not HAVE_X11 */ + + +x_set_mouse_position (s, x, y) + struct screen *s; + int x, y; +{ + int pix_x, pix_y; + + x_raise_screen (s); + + 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; + + BLOCK_INPUT; + x_mouse_x = x; + x_mouse_y = y; + + XWarpMousePointer (s->display.x->window_desc, pix_x, pix_y); + UNBLOCK_INPUT; +} + +#ifdef HAVE_X11 +x_focus_on_screen (s) + struct screen *s; +{ + x_raise_screen (s); + XSetInputFocus (x_current_display, s->display.x->window_desc, + RevertToPointerRoot, CurrentTime); +} + +x_unfocus_screen (s) + struct screen *s; +{ + if (x_focus_screen == s) + XSetInputFocus (x_current_display, PointerRoot, + RevertToPointerRoot, CurrentTime); +} + +#endif + +/* Raise screen S. */ + +x_raise_screen (s) + struct screen *s; +{ + if (s->visible) + { + BLOCK_INPUT; + XRaiseWindow (XDISPLAY s->display.x->window_desc); + XFlushQueue (); + UNBLOCK_INPUT; + } +} + +/* Lower screen S. */ + +x_lower_screen (s) + struct screen *s; +{ + if (s->visible) + { + BLOCK_INPUT; + XLowerWindow (XDISPLAY s->display.x->window_desc); + XFlushQueue (); + UNBLOCK_INPUT; + } +} + +/* Change from withdrawn state to mapped state. */ + +x_make_screen_visible (s) + struct screen *s; +{ + int mask; + + if (s->visible) + { + BLOCK_INPUT; + XRaiseWindow (XDISPLAY s->display.x->window_desc); + XFlushQueue (); + UNBLOCK_INPUT; + return; + } + + BLOCK_INPUT; +#ifdef HAVE_X11 + + if (! EQ (Vx_no_window_manager, Qt)) + x_wm_set_window_state (s, 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); + + /* Handled by the MapNotify event for X11 */ + s->visible = 1; + s->iconified = 0; + + /* NOTE: this may cause problems for the first screen. */ + XTcursor_to (0, 0); +#endif /* not HAVE_X11 */ + + XRaiseWindow (XDISPLAY s->display.x->window_desc); + XFlushQueue (); + UNBLOCK_INPUT; +} + +/* Change from mapped state to withdrawn state. */ + +x_make_screen_invisible (s) + struct screen *s; +{ + int mask; + + if (! s->visible) + return; + + BLOCK_INPUT; +#ifdef HAVE_X11 +#if 0 + if (! EQ (Vx_no_window_manager, Qt)) + { + XUnmapEvent 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); + } + + /* 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 + + /* 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 + XUnmapWindow (XDISPLAY s->display.x->window_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 */ + + 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; +{ + int mask; + + if (s->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))) + { + 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; + + if (! XSendEvent (x_current_display, + DefaultRootWindow (x_current_display), + False, + SubstructureRedirectMask | SubstructureNotifyMask, + &message)) + { + UNBLOCK_INPUT_RESIGNAL; + error ("Can't notify window manager of iconification."); + } + } +#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) + { + XMapWindow (XDISPLAY s->display.x->icon_desc); + refreshicon (s); + } +#endif /* X10 */ + + XFlushQueue (); + UNBLOCK_INPUT; +} + +/* Destroy the X window of screen S. + DISPL is the former s->display (since s->display + has already been nulled out). */ + +x_destroy_window (s, displ) + struct screen *s; + union display displ; +{ + int mask; + + BLOCK_INPUT; + if (displ.x->icon_desc != 0) + XDestroyWindow (XDISPLAY displ.x->icon_desc); + XDestroyWindow (XDISPLAY displ.x->window_desc); + XFlushQueue (); + UNBLOCK_INPUT; + + free (displ.x); + if (s == x_focus_screen) + x_focus_screen = 0; +} + +#ifndef HAVE_X11 + +/* Manage event queues. + + This code is only used by the X10 support. + + We cannot leave events in the X queue and get them when we are ready + because X does not provide a subroutine to get only a certain kind + of event but not block if there are no queued events of that kind. + + Therefore, we must examine events as they come in and copy events + of certain kinds into our private queues. + + All ExposeRegion events are put in x_expose_queue. + All ButtonPressed and ButtonReleased events are put in x_mouse_queue. */ + + +/* Write the event *P_XREP into the event queue *QUEUE. + If the queue is full, do nothing, but return nonzero. */ + +int +enqueue_event (p_xrep, queue) + register XEvent *p_xrep; + register struct event_queue *queue; +{ + int newindex = queue->windex + 1; + if (newindex == EVENT_BUFFER_SIZE) + newindex = 0; + if (newindex == queue->rindex) + return -1; + queue->xrep[queue->windex] = *p_xrep; + queue->windex = newindex; + return 0; +} + +/* Fetch the next event from queue *QUEUE and store it in *P_XREP. + If *QUEUE is empty, do nothing and return 0. */ + +int +dequeue_event (p_xrep, queue) + register XEvent *p_xrep; + register struct event_queue *queue; +{ + if (queue->windex == queue->rindex) + return 0; + *p_xrep = queue->xrep[queue->rindex++]; + if (queue->rindex == EVENT_BUFFER_SIZE) + queue->rindex = 0; + return 1; +} + +/* Return the number of events buffered in *QUEUE. */ + +int +queue_event_count (queue) + register struct event_queue *queue; +{ + int tem = queue->windex - queue->rindex; + if (tem >= 0) + return tem; + return EVENT_BUFFER_SIZE + tem; +} + +/* Return nonzero if mouse input is pending. */ + +int +mouse_event_pending_p () +{ + return queue_event_count (&x_mouse_queue); +} +#endif + +#ifdef HAVE_X11 + +x_wm_set_size_hint (s, prompting) + struct screen *s; + long prompting; +{ + 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); + + if (prompting) + size_hints.flags |= prompting; + else + { + XSizeHints hints; /* Sometimes I hate X Windows... */ + + XGetNormalHints (x_current_display, window, &hints); + if (hints.flags & PSize) + size_hints.flags |= PSize; + if (hints.flags & PPosition) + size_hints.flags |= PPosition; + if (hints.flags & USPosition) + size_hints.flags |= USPosition; + if (hints.flags & USSize) + size_hints.flags |= USSize; + } + +#if 0 /* R3 */ + 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; + int state; +{ + XWMHints wm_hints; + Window window = s->display.x->window_desc; + + wm_hints.flags = StateHint; + wm_hints.initial_state = state; + XSetWMHints (x_current_display, window, &wm_hints); +} + +x_wm_set_icon_pixmap (s, icon_pixmap) + struct screen *s; + Pixmap icon_pixmap; +{ + XWMHints wm_hints; + Window window = s->display.x->window_desc; + + wm_hints.flags = IconPixmapHint; + wm_hints.icon_pixmap = icon_pixmap; + XSetWMHints (x_current_display, window, &wm_hints); +} + +x_wm_set_icon_position (s, icon_x, icon_y) + struct screen *s; + int icon_x, icon_y; +{ + XWMHints wm_hints; + Window window = s->display.x->window_desc; + + wm_hints.flags = IconPositionHint; + wm_hints.icon_x = icon_x; + wm_hints.icon_y = icon_y; + XSetWMHints (x_current_display, window, &wm_hints); +} + + +static void +init_input_symbols () +{ + Qmapped_screen = intern ("mapped-screen"); + Qunmapped_screen = intern ("unmapped-screen"); + Qexited_scrollbar = intern ("exited-scrollbar"); + Qexited_window = intern ("exited-window"); + Qredraw_screen = intern ("redraw-screen"); + Qmouse_moved = intern ("mouse-moved"); + Qmouse_click = intern ("mouse-click"); + Qscrollbar_click = intern ("scrollbar-click"); +} + +void +x_term_init (display_name) + char *display_name; +{ + Lisp_Object screen; + char *defaultvalue; +#ifdef F_SETOWN + extern int old_fcntl_owner; +#endif + + 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", + display_name); + +#ifdef HAVE_X11 + { + int hostname_size = MAXHOSTNAMELEN + 1; + + hostname = (char *) xmalloc (hostname_size); + +#if 0 + XSetAfterFunction (x_current_display, x_trace_wire); +#endif + + invocation_name = (char *) + XSTRING (Ffile_name_nondirectory (Fcar (Vcommand_line_args)))->data; + + /* Try to get the host name; if the buffer is too short, try + again. Apparently, the only indication gethostname gives of + whether the buffer was large enough is the presence or absence + of a '\0' in the string. Eech. */ + for (;;) + { + gethostname (hostname, hostname_size - 1); + hostname[hostname_size - 1] = '\0'; + + /* Was the buffer large enough for gethostname to store the '\0'? */ + if (strlen (hostname) < hostname_size - 1) + break; + + hostname_size <<= 1; + hostname = (char *) xrealloc (hostname, hostname_size); + } + id_name = (char *) xmalloc (strlen (invocation_name) + + strlen (hostname) + + 2); + sprintf (id_name, "%s@%s", invocation_name, hostname); + } + + dup2 (ConnectionNumber (x_current_display), 0); + close (ConnectionNumber (x_current_display)); + ConnectionNumber (x_current_display) = 0; +#endif /* HAVE_X11 */ + +#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 + fcntl (0, F_SETOWN, getpid ()); +#endif /* F_SETOWN_SOCK_NEG */ +#endif /* F_SETOWN */ + +#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); + + expose_all_windows = 0; + + clear_screen_hook = XTclear_screen; + clear_end_of_line_hook = XTclear_end_of_line; + ins_del_lines_hook = XTins_del_lines; + change_line_highlight_hook = XTchange_line_highlight; + insert_glyphs_hook = XTinsert_glyphs; + write_glyphs_hook = XTwrite_glyphs; + delete_glyphs_hook = XTdelete_glyphs; + ring_bell_hook = XTring_bell; + reset_terminal_modes_hook = XTreset_terminal_modes; + set_terminal_modes_hook = XTset_terminal_modes; + update_begin_hook = XTupdate_begin; + update_end_hook = XTupdate_end; + set_terminal_window_hook = XTset_terminal_window; + read_socket_hook = XTread_socket; + cursor_to_hook = XTcursor_to; + reassert_line_highlight_hook = XTreassert_line_highlight; + mouse_tracking_enable_hook = XTmouse_tracking_enable; + + scroll_region_ok = 1; /* we'll scroll partial screens */ + 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 + off the bottom */ + baud_rate = 19200; + + init_input_symbols (); + + XHandleError (x_error_handler); + XHandleIOError (x_error_handler); + + /* Disable Window Change signals; they are handled by X events. */ +#ifdef SIGWINCH + signal (SIGWINCH, SIG_DFL); +#endif /* SIGWINCH */ + + signal (SIGPIPE, x_error_handler); +} +#endif /* HAVE_X11 */ +#endif /* HAVE_X_WINDOWS */