# HG changeset patch # User Jim Blandy # Date 682131887 0 # Node ID 6e0510766e669da17c5f65c22779037346aa40e0 # Parent 498bcec1cf3a64c58d9ba24642310f9d9fedce3e Initial revision diff -r 498bcec1cf3a -r 6e0510766e66 src/xfns.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/xfns.c Wed Aug 14 01:04:47 1991 +0000 @@ -0,0 +1,4516 @@ +/* Functions for the X window system. + Copyright (C) 1989 Free Software Foundation. + +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. */ + +/* Completely rewritten by Richard Stallman. */ + +/* Rewritten for X11 by Joseph Arceneaux */ + +#if 0 +#include +#endif +#include +#include "config.h" +#include "lisp.h" +#include "xterm.h" +#include "screen.h" +#include "window.h" +#include "buffer.h" +#include "dispextern.h" +#include "xscrollbar.h" + +#ifdef HAVE_X_WINDOWS +extern void abort (); + +void x_set_screen_param (); + +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define max(a,b) ((a) > (b) ? (a) : (b)) + +#ifdef HAVE_X11 +/* X Resource data base */ +static XrmDatabase xrdb; + +/* The class of this X application. */ +#define EMACS_CLASS "Emacs" + +/* The class of Emacs screens. */ +#define SCREEN_CLASS "Screen" + +/* Title name and application name for X stuff. */ +extern char *id_name; +extern Lisp_Object invocation_name; + +/* The background and shape of the mouse pointer, and shape when not + over text or in the modeline. */ +Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape; + +/* Color of chars displayed in cursor box. */ +Lisp_Object Vx_cursor_fore_pixel; + +/* If non-nil, use vertical bar cursor. */ +Lisp_Object Vbar_cursor; + +/* The X Visual we are using for X windows (the default) */ +Visual *screen_visual; + +/* How many screens this X display has. */ +int x_screen_count; + +/* The vendor supporting this X server. */ +Lisp_Object Vx_vendor; + +/* The vendor's release number for this X server. */ +int x_release; + +/* Height of this X screen in pixels. */ +int x_screen_height; + +/* Height of this X screen in millimeters. */ +int x_screen_height_mm; + +/* Width of this X screen in pixels. */ +int x_screen_width; + +/* Width of this X screen in millimeters. */ +int x_screen_width_mm; + +/* Does this X screen do backing store? */ +Lisp_Object Vx_backing_store; + +/* Does this X screen do save-unders? */ +int x_save_under; + +/* Number of planes for this screen. */ +int x_screen_planes; + +/* X Visual type of this screen. */ +Lisp_Object Vx_screen_visual; + +/* Non nil if no window manager is in use. */ +Lisp_Object Vx_no_window_manager; + +static char *x_visual_strings[] = + { + "StaticGray", + "GrayScale", + "StaticColor", + "PseudoColor", + "TrueColor", + "DirectColor" + }; + +/* `t' if a mouse button is depressed. */ + +Lisp_Object Vmouse_depressed; + +/* Atom for indicating window state to the window manager. */ +Atom Xatom_wm_change_state; + +/* When emacs became the selection owner. */ +extern Time x_begin_selection_own; + +/* The value of the current emacs selection. */ +extern Lisp_Object Vx_selection_value; + +/* Emacs' selection property identifier. */ +extern Atom Xatom_emacs_selection; + +/* Clipboard selection atom. */ +extern Atom Xatom_clipboard_selection; + +/* Clipboard atom. */ +extern Atom Xatom_clipboard; + +/* Atom for indicating incremental selection transfer. */ +extern Atom Xatom_incremental; + +/* Atom for indicating multiple selection request list */ +extern Atom Xatom_multiple; + +/* Atom for what targets emacs handles. */ +extern Atom Xatom_targets; + +/* Atom for indicating timstamp selection request */ +extern Atom Xatom_timestamp; + +/* Atom requesting we delete our selection. */ +extern Atom Xatom_delete; + +/* Selection magic. */ +extern Atom Xatom_insert_selection; + +/* Type of property for INSERT_SELECTION. */ +extern Atom Xatom_pair; + +/* More selection magic. */ +extern Atom Xatom_insert_property; + +/* Atom for indicating property type TEXT */ +extern Atom Xatom_text; + +#else /* X10 */ + +/* Default size of an Emacs window without scroll bar. */ +static char *default_window = "=80x24+0+0"; + +#define MAXICID 80 +char iconidentity[MAXICID]; +#define ICONTAG "emacs@" +char minibuffer_iconidentity[MAXICID]; +#define MINIBUFFER_ICONTAG "minibuffer@" + +#endif /* X10 */ + +/* The last 23 bits of the timestamp of the last mouse button event. */ +Time mouse_timestamp; + +Lisp_Object Qundefined_color; +Lisp_Object Qx_screen_parameter; + +extern Lisp_Object Vwindow_system_version; + +/* Mouse map for clicks in windows. */ +extern Lisp_Object Vglobal_mouse_map; + +/* Points to table of defined typefaces. */ +struct face *x_face_table[MAX_FACES_AND_GLYPHS]; + +/* Return the Emacs screen-object corresponding to an X window. + It could be the screen's main window or an icon window. */ + +struct screen * +x_window_to_screen (wdesc) + int wdesc; +{ + Lisp_Object tail, screen; + struct screen *s; + + for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr) + { + screen = XCONS (tail)->car; + if (XTYPE (screen) != Lisp_Screen) + continue; + s = XSCREEN (screen); + if (s->display.x->window_desc == wdesc + || s->display.x->icon_desc == wdesc) + return s; + } + return 0; +} + +/* A symbol indicating which part of the screen the mouse is in. */ +Lisp_Object Vmouse_screen_part; + +Lisp_Object Qtext_part; +Lisp_Object Qmodeline_part; + +Lisp_Object Qvscrollbar_part; +Lisp_Object Qvslider_part; +Lisp_Object Qvthumbup_part; +Lisp_Object Qvthumbdown_part; + +Lisp_Object Qhscrollbar_part; +Lisp_Object Qhslider_part; +Lisp_Object Qhthumbleft_part; +Lisp_Object Qhthumbright_part; + +/* Map an X window that implements a scroll bar to the Emacs screen it + belongs to. Also store in *PART a symbol identifying which part of + the scroll bar it is. */ + +struct screen * +x_window_to_scrollbar (wdesc, part_ptr, prefix_ptr) + int wdesc; + Lisp_Object *part_ptr; + enum scroll_bar_prefix *prefix_ptr; +{ + Lisp_Object tail, screen; + struct screen *s; + + for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr) + { + screen = XCONS (tail)->car; + if (XTYPE (screen) != Lisp_Screen) + continue; + + s = XSCREEN (screen); + if (part_ptr == 0 && prefix_ptr == 0) + return s; + + if (s->display.x->v_scrollbar == wdesc) + { + *part_ptr = Qvscrollbar_part; + *prefix_ptr = VSCROLL_BAR_PREFIX; + return s; + } + else if (s->display.x->v_slider == wdesc) + { + *part_ptr = Qvslider_part; + *prefix_ptr = VSCROLL_SLIDER_PREFIX; + return s; + } + else if (s->display.x->v_thumbup == wdesc) + { + *part_ptr = Qvthumbup_part; + *prefix_ptr = VSCROLL_THUMBUP_PREFIX; + return s; + } + else if (s->display.x->v_thumbdown == wdesc) + { + *part_ptr = Qvthumbdown_part; + *prefix_ptr = VSCROLL_THUMBDOWN_PREFIX; + return s; + } + else if (s->display.x->h_scrollbar == wdesc) + { + *part_ptr = Qhscrollbar_part; + *prefix_ptr = HSCROLL_BAR_PREFIX; + return s; + } + else if (s->display.x->h_slider == wdesc) + { + *part_ptr = Qhslider_part; + *prefix_ptr = HSCROLL_SLIDER_PREFIX; + return s; + } + else if (s->display.x->h_thumbleft == wdesc) + { + *part_ptr = Qhthumbleft_part; + *prefix_ptr = HSCROLL_THUMBLEFT_PREFIX; + return s; + } + else if (s->display.x->h_thumbright == wdesc) + { + *part_ptr = Qhthumbright_part; + *prefix_ptr = HSCROLL_THUMBRIGHT_PREFIX; + return s; + } + } + return 0; +} + +/* Connect the screen-parameter names for X screens + to the ways of passing the parameter values to the window system. + + The name of a parameter, as a Lisp symbol, + has an `x-screen-parameter' property which is an integer in Lisp + but can be interpreted as an `enum x_screen_parm' in C. */ + +enum x_screen_parm +{ + X_PARM_FOREGROUND_COLOR, + X_PARM_BACKGROUND_COLOR, + X_PARM_MOUSE_COLOR, + X_PARM_CURSOR_COLOR, + X_PARM_BORDER_COLOR, + X_PARM_ICON_TYPE, + X_PARM_FONT, + X_PARM_BORDER_WIDTH, + X_PARM_INTERNAL_BORDER_WIDTH, + X_PARM_NAME, + X_PARM_AUTORAISE, + X_PARM_AUTOLOWER, + X_PARM_VERT_SCROLLBAR, + X_PARM_HORIZ_SCROLLBAR, +}; + + +struct x_screen_parm_table +{ + char *name; + void (*setter)( /* struct screen *screen, Lisp_Object val, oldval */ ); +}; + +void x_set_foreground_color (); +void x_set_background_color (); +void x_set_mouse_color (); +void x_set_cursor_color (); +void x_set_border_color (); +void x_set_icon_type (); +void x_set_font (); +void x_set_border_width (); +void x_set_internal_border_width (); +void x_set_name (); +void x_set_autoraise (); +void x_set_autolower (); +void x_set_vertical_scrollbar (); +void x_set_horizontal_scrollbar (); + +static struct x_screen_parm_table x_screen_parms[] = +{ + "foreground-color", x_set_foreground_color, + "background-color", x_set_background_color, + "mouse-color", x_set_mouse_color, + "cursor-color", x_set_cursor_color, + "border-color", x_set_border_color, + "icon-type", x_set_icon_type, + "font", x_set_font, + "border-width", x_set_border_width, + "internal-border-width", x_set_internal_border_width, + "name", x_set_name, + "autoraise", x_set_autoraise, + "autolower", x_set_autolower, + "vertical-scrollbar", x_set_vertical_scrollbar, + "horizontal-scrollbar", x_set_horizontal_scrollbar, +}; + +/* Attach the `x-screen-parameter' properties to + the Lisp symbol names of parameters relevant to X. */ + +init_x_parm_symbols () +{ + int i; + + Qx_screen_parameter = intern ("x-screen-parameter"); + + for (i = 0; i < sizeof (x_screen_parms)/sizeof (x_screen_parms[0]); i++) + Fput (intern (x_screen_parms[i].name), Qx_screen_parameter, + make_number (i)); +} + +/* Report to X that a screen parameter of screen S is being set or changed. + PARAM is the symbol that says which parameter. + VAL is the new value. + OLDVAL is the old value. + If the parameter is not specially recognized, do nothing; + otherwise the `x_set_...' function for this parameter. */ + +void +x_set_screen_param (s, param, val, oldval) + register struct screen *s; + Lisp_Object param; + register Lisp_Object val; + register Lisp_Object oldval; +{ + register Lisp_Object tem; + tem = Fget (param, Qx_screen_parameter); + if (XTYPE (tem) == Lisp_Int + && XINT (tem) >= 0 + && XINT (tem) < sizeof (x_screen_parms)/sizeof (x_screen_parms[0])) + (*x_screen_parms[XINT (tem)].setter)(s, val, oldval); +} + +/* Insert a description of internally-recorded parameters of screen X + into the parameter alist *ALISTPTR that is to be given to the user. + Only parameters that are specific to the X window system + and whose values are not correctly recorded in the screen's + param_alist need to be considered here. */ + +x_report_screen_params (s, alistptr) + struct screen *s; + Lisp_Object *alistptr; +{ + char buf[16]; + + store_in_alist (alistptr, "left", make_number (s->display.x->left_pos)); + store_in_alist (alistptr, "top", make_number (s->display.x->top_pos)); + store_in_alist (alistptr, "border-width", + make_number (s->display.x->border_width)); + store_in_alist (alistptr, "internal-border-width", + make_number (s->display.x->internal_border_width)); + sprintf (buf, "%d", s->display.x->window_desc); + store_in_alist (alistptr, "window-id", + build_string (buf)); +} + +/* Decide if color named COLOR is valid for the display + associated with the selected screen. */ +int +defined_color (color, color_def) + char *color; + Color *color_def; +{ + register int foo; + Colormap screen_colormap; + + BLOCK_INPUT; +#ifdef HAVE_X11 + screen_colormap + = DefaultColormap (x_current_display, XDefaultScreen (x_current_display)); + + foo = XParseColor (x_current_display, screen_colormap, + color, color_def) + && XAllocColor (x_current_display, screen_colormap, color_def); +#else + foo = XParseColor (color, color_def) && XGetHardwareColor (color_def); +#endif /* not HAVE_X11 */ + UNBLOCK_INPUT; + + if (foo) + return 1; + else + return 0; +} + +/* Given a string ARG naming a color, compute a pixel value from it + suitable for screen S. + If S is not a color screen, return DEF (default) regardless of what + ARG says. */ + +int +x_decode_color (arg, def) + Lisp_Object arg; + int def; +{ + Color cdef; + + CHECK_STRING (arg, 0); + + if (strcmp (XSTRING (arg)->data, "black") == 0) + return BLACK_PIX_DEFAULT; + else if (strcmp (XSTRING (arg)->data, "white") == 0) + return WHITE_PIX_DEFAULT; + +#ifdef HAVE_X11 + if (XFASTINT (x_screen_planes) <= 2) + return def; +#else + if (DISPLAY_CELLS <= 2) + return def; +#endif + + if (defined_color (XSTRING (arg)->data, &cdef)) + return cdef.pixel; + else + Fsignal (Qundefined_color, Fcons (arg, Qnil)); +} + +/* Functions called only from `x_set_screen_param' + to set individual parameters. + + If s->display.x->window_desc is 0, + the screen is being created and its X-window does not exist yet. + In that case, just record the parameter's new value + in the standard place; do not attempt to change the window. */ + +void +x_set_foreground_color (s, arg, oldval) + struct screen *s; + Lisp_Object arg, oldval; +{ + s->display.x->foreground_pixel = x_decode_color (arg, BLACK_PIX_DEFAULT); + if (s->display.x->window_desc != 0) + { +#ifdef HAVE_X11 + BLOCK_INPUT; + XSetForeground (x_current_display, s->display.x->normal_gc, + s->display.x->foreground_pixel); + XSetBackground (x_current_display, s->display.x->reverse_gc, + s->display.x->foreground_pixel); + if (s->display.x->v_scrollbar) + { + Pixmap up_arrow_pixmap, down_arrow_pixmap, slider_pixmap; + + XSetWindowBorder (x_current_display, s->display.x->v_scrollbar, + s->display.x->foreground_pixel); + + slider_pixmap = + XCreatePixmapFromBitmapData (XDISPLAY s->display.x->window_desc, + gray_bits, 16, 16, + s->display.x->foreground_pixel, + s->display.x->background_pixel, + DefaultDepth (x_current_display, + XDefaultScreen (x_current_display))); + up_arrow_pixmap = + XCreatePixmapFromBitmapData (XDISPLAY s->display.x->window_desc, + up_arrow_bits, 16, 16, + s->display.x->foreground_pixel, + s->display.x->background_pixel, + DefaultDepth (x_current_display, + XDefaultScreen (x_current_display))); + down_arrow_pixmap = + XCreatePixmapFromBitmapData (XDISPLAY s->display.x->window_desc, + down_arrow_bits, 16, 16, + s->display.x->foreground_pixel, + s->display.x->background_pixel, + DefaultDepth (x_current_display, + XDefaultScreen (x_current_display))); + + XSetWindowBackgroundPixmap (XDISPLAY s->display.x->v_thumbup, + up_arrow_pixmap); + XSetWindowBackgroundPixmap (XDISPLAY s->display.x->v_thumbdown, + down_arrow_pixmap); + XSetWindowBackgroundPixmap (XDISPLAY s->display.x->v_slider, + slider_pixmap); + + XClearWindow (XDISPLAY s->display.x->v_thumbup); + XClearWindow (XDISPLAY s->display.x->v_thumbdown); + XClearWindow (XDISPLAY s->display.x->v_slider); + + XFreePixmap (x_current_display, down_arrow_pixmap); + XFreePixmap (x_current_display, up_arrow_pixmap); + XFreePixmap (x_current_display, slider_pixmap); + } + if (s->display.x->h_scrollbar) + { + Pixmap left_arrow_pixmap, right_arrow_pixmap, slider_pixmap; + + XSetWindowBorder (x_current_display, s->display.x->h_scrollbar, + s->display.x->foreground_pixel); + + slider_pixmap = + XCreatePixmapFromBitmapData (XDISPLAY s->display.x->window_desc, + gray_bits, 16, 16, + s->display.x->foreground_pixel, + s->display.x->background_pixel, + DefaultDepth (x_current_display, + XDefaultScreen (x_current_display))); + + left_arrow_pixmap = + XCreatePixmapFromBitmapData (XDISPLAY s->display.x->window_desc, + up_arrow_bits, 16, 16, + s->display.x->foreground_pixel, + s->display.x->background_pixel, + DefaultDepth (x_current_display, + XDefaultScreen (x_current_display))); + right_arrow_pixmap = + XCreatePixmapFromBitmapData (XDISPLAY s->display.x->window_desc, + down_arrow_bits, 16, 16, + s->display.x->foreground_pixel, + s->display.x->background_pixel, + DefaultDepth (x_current_display, + XDefaultScreen (x_current_display))); + + XSetWindowBackgroundPixmap (XDISPLAY s->display.x->h_slider, + slider_pixmap); + XSetWindowBackgroundPixmap (XDISPLAY s->display.x->h_thumbleft, + left_arrow_pixmap); + XSetWindowBackgroundPixmap (XDISPLAY s->display.x->h_thumbright, + right_arrow_pixmap); + + XClearWindow (XDISPLAY s->display.x->h_thumbleft); + XClearWindow (XDISPLAY s->display.x->h_thumbright); + XClearWindow (XDISPLAY s->display.x->h_slider); + + XFreePixmap (x_current_display, slider_pixmap); + XFreePixmap (x_current_display, left_arrow_pixmap); + XFreePixmap (x_current_display, right_arrow_pixmap); + } + UNBLOCK_INPUT; +#endif /* HAVE_X11 */ + if (s->visible) + redraw_screen (s); + } +} + +void +x_set_background_color (s, arg, oldval) + struct screen *s; + Lisp_Object arg, oldval; +{ + Pixmap temp; + int mask; + + s->display.x->background_pixel = x_decode_color (arg, WHITE_PIX_DEFAULT); + + if (s->display.x->window_desc != 0) + { + BLOCK_INPUT; +#ifdef HAVE_X11 + /* The main screen. */ + XSetBackground (x_current_display, s->display.x->normal_gc, + s->display.x->background_pixel); + XSetForeground (x_current_display, s->display.x->reverse_gc, + s->display.x->background_pixel); + XSetWindowBackground (x_current_display, s->display.x->window_desc, + s->display.x->background_pixel); + + /* Scroll bars. */ + if (s->display.x->v_scrollbar) + { + Pixmap up_arrow_pixmap, down_arrow_pixmap, slider_pixmap; + + XSetWindowBackground (x_current_display, s->display.x->v_scrollbar, + s->display.x->background_pixel); + + slider_pixmap = + XCreatePixmapFromBitmapData (XDISPLAY s->display.x->window_desc, + gray_bits, 16, 16, + s->display.x->foreground_pixel, + s->display.x->background_pixel, + DefaultDepth (x_current_display, + XDefaultScreen (x_current_display))); + up_arrow_pixmap = + XCreatePixmapFromBitmapData (XDISPLAY s->display.x->window_desc, + up_arrow_bits, 16, 16, + s->display.x->foreground_pixel, + s->display.x->background_pixel, + DefaultDepth (x_current_display, + XDefaultScreen (x_current_display))); + down_arrow_pixmap = + XCreatePixmapFromBitmapData (XDISPLAY s->display.x->window_desc, + down_arrow_bits, 16, 16, + s->display.x->foreground_pixel, + s->display.x->background_pixel, + DefaultDepth (x_current_display, + XDefaultScreen (x_current_display))); + + XSetWindowBackgroundPixmap (XDISPLAY s->display.x->v_thumbup, + up_arrow_pixmap); + XSetWindowBackgroundPixmap (XDISPLAY s->display.x->v_thumbdown, + down_arrow_pixmap); + XSetWindowBackgroundPixmap (XDISPLAY s->display.x->v_slider, + slider_pixmap); + + XClearWindow (XDISPLAY s->display.x->v_thumbup); + XClearWindow (XDISPLAY s->display.x->v_thumbdown); + XClearWindow (XDISPLAY s->display.x->v_slider); + + XFreePixmap (x_current_display, down_arrow_pixmap); + XFreePixmap (x_current_display, up_arrow_pixmap); + XFreePixmap (x_current_display, slider_pixmap); + } + if (s->display.x->h_scrollbar) + { + Pixmap left_arrow_pixmap, right_arrow_pixmap, slider_pixmap; + + XSetWindowBackground (x_current_display, s->display.x->h_scrollbar, + s->display.x->background_pixel); + + slider_pixmap = + XCreatePixmapFromBitmapData (XDISPLAY s->display.x->window_desc, + gray_bits, 16, 16, + s->display.x->foreground_pixel, + s->display.x->background_pixel, + DefaultDepth (x_current_display, + XDefaultScreen (x_current_display))); + + left_arrow_pixmap = + XCreatePixmapFromBitmapData (XDISPLAY s->display.x->window_desc, + up_arrow_bits, 16, 16, + s->display.x->foreground_pixel, + s->display.x->background_pixel, + DefaultDepth (x_current_display, + XDefaultScreen (x_current_display))); + right_arrow_pixmap = + XCreatePixmapFromBitmapData (XDISPLAY s->display.x->window_desc, + down_arrow_bits, 16, 16, + s->display.x->foreground_pixel, + s->display.x->background_pixel, + DefaultDepth (x_current_display, + XDefaultScreen (x_current_display))); + + XSetWindowBackgroundPixmap (XDISPLAY s->display.x->h_slider, + slider_pixmap); + XSetWindowBackgroundPixmap (XDISPLAY s->display.x->h_thumbleft, + left_arrow_pixmap); + XSetWindowBackgroundPixmap (XDISPLAY s->display.x->h_thumbright, + right_arrow_pixmap); + + XClearWindow (XDISPLAY s->display.x->h_thumbleft); + XClearWindow (XDISPLAY s->display.x->h_thumbright); + XClearWindow (XDISPLAY s->display.x->h_slider); + + XFreePixmap (x_current_display, slider_pixmap); + XFreePixmap (x_current_display, left_arrow_pixmap); + XFreePixmap (x_current_display, right_arrow_pixmap); + } +#else + temp = XMakeTile (s->display.x->background_pixel); + XChangeBackground (s->display.x->window_desc, temp); + XFreePixmap (temp); +#endif /* not HAVE_X11 */ + UNBLOCK_INPUT; + + if (s->visible) + redraw_screen (s); + } +} + +void +x_set_mouse_color (s, arg, oldval) + struct screen *s; + Lisp_Object arg, oldval; +{ + Cursor cursor, nontext_cursor, mode_cursor; + int mask_color; + + if (!EQ (Qnil, arg)) + s->display.x->mouse_pixel = x_decode_color (arg, BLACK_PIX_DEFAULT); + mask_color = s->display.x->background_pixel; + /* No invisible pointers. */ + if (mask_color == s->display.x->mouse_pixel + && mask_color == s->display.x->background_pixel) + s->display.x->mouse_pixel = s->display.x->foreground_pixel; + + BLOCK_INPUT; +#ifdef HAVE_X11 + if (!EQ (Qnil, Vx_pointer_shape)) + { + CHECK_NUMBER (Vx_pointer_shape, 0); + cursor = XCreateFontCursor (x_current_display, XINT (Vx_pointer_shape)); + } + else + cursor = XCreateFontCursor (x_current_display, XC_xterm); + + if (!EQ (Qnil, Vx_nontext_pointer_shape)) + { + CHECK_NUMBER (Vx_nontext_pointer_shape, 0); + nontext_cursor = XCreateFontCursor (x_current_display, + XINT (Vx_nontext_pointer_shape)); + } + else + nontext_cursor = XCreateFontCursor (x_current_display, XC_left_ptr); + + if (!EQ (Qnil, Vx_mode_pointer_shape)) + { + CHECK_NUMBER (Vx_mode_pointer_shape, 0); + mode_cursor = XCreateFontCursor (x_current_display, + XINT (Vx_mode_pointer_shape)); + } + else + mode_cursor = XCreateFontCursor (x_current_display, XC_xterm); + + { + XColor fore_color, back_color; + + fore_color.pixel = s->display.x->mouse_pixel; + back_color.pixel = mask_color; + XQueryColor (x_current_display, + DefaultColormap (x_current_display, + DefaultScreen (x_current_display)), + &fore_color); + XQueryColor (x_current_display, + DefaultColormap (x_current_display, + DefaultScreen (x_current_display)), + &back_color); + XRecolorCursor (x_current_display, cursor, + &fore_color, &back_color); + XRecolorCursor (x_current_display, nontext_cursor, + &fore_color, &back_color); + XRecolorCursor (x_current_display, mode_cursor, + &fore_color, &back_color); + } +#else /* X10 */ + cursor = XCreateCursor (16, 16, MouseCursor, MouseMask, + 0, 0, + s->display.x->mouse_pixel, + s->display.x->background_pixel, + GXcopy); +#endif /* X10 */ + + if (s->display.x->window_desc != 0) + { + XDefineCursor (XDISPLAY s->display.x->window_desc, cursor); + } + + if (cursor != s->display.x->text_cursor && s->display.x->text_cursor != 0) + XFreeCursor (XDISPLAY s->display.x->text_cursor); + s->display.x->text_cursor = cursor; +#ifdef HAVE_X11 + if (nontext_cursor != s->display.x->nontext_cursor + && s->display.x->nontext_cursor != 0) + XFreeCursor (XDISPLAY s->display.x->nontext_cursor); + s->display.x->nontext_cursor = nontext_cursor; + + if (mode_cursor != s->display.x->modeline_cursor + && s->display.x->modeline_cursor != 0) + XFreeCursor (XDISPLAY s->display.x->modeline_cursor); + s->display.x->modeline_cursor = mode_cursor; +#endif /* HAVE_X11 */ + + XFlushQueue (); + UNBLOCK_INPUT; +} + +void +x_set_cursor_color (s, arg, oldval) + struct screen *s; + Lisp_Object arg, oldval; +{ + unsigned long fore_pixel; + + if (!EQ (Vx_cursor_fore_pixel, Qnil)) + fore_pixel = x_decode_color (Vx_cursor_fore_pixel, WHITE_PIX_DEFAULT); + else + fore_pixel = s->display.x->background_pixel; + s->display.x->cursor_pixel = x_decode_color (arg, BLACK_PIX_DEFAULT); + /* No invisible cursors */ + if (s->display.x->cursor_pixel == s->display.x->background_pixel) + { + s->display.x->cursor_pixel == s->display.x->mouse_pixel; + if (s->display.x->cursor_pixel == fore_pixel) + fore_pixel = s->display.x->background_pixel; + } + + if (s->display.x->window_desc != 0) + { +#ifdef HAVE_X11 + BLOCK_INPUT; + XSetBackground (x_current_display, s->display.x->cursor_gc, + s->display.x->cursor_pixel); + XSetForeground (x_current_display, s->display.x->cursor_gc, + fore_pixel); + UNBLOCK_INPUT; +#endif /* HAVE_X11 */ + + if (s->visible) + { + x_display_cursor (s, 0); + x_display_cursor (s, 1); + } + } +} + +/* Set the border-color of screen S to value described by ARG. + ARG can be a string naming a color. + The border-color is used for the border that is drawn by the X server. + Note that this does not fully take effect if done before + S has an x-window; it must be redone when the window is created. + + Note: this is done in two routines because of the way X10 works. + + Note: under X11, this is normally the province of the window manager, + and so emacs' border colors may be overridden. */ + +void +x_set_border_color (s, arg, oldval) + struct screen *s; + Lisp_Object arg, oldval; +{ + unsigned char *str; + int pix; + + CHECK_STRING (arg, 0); + str = XSTRING (arg)->data; + +#ifndef HAVE_X11 + if (!strcmp (str, "grey") || !strcmp (str, "Grey") + || !strcmp (str, "gray") || !strcmp (str, "Gray")) + pix = -1; + else +#endif /* X10 */ + + pix = x_decode_color (arg, BLACK_PIX_DEFAULT); + + x_set_border_pixel (s, pix); +} + +/* Set the border-color of screen S to pixel value PIX. + Note that this does not fully take effect if done before + S has an x-window. */ + +x_set_border_pixel (s, pix) + struct screen *s; + int pix; +{ + s->display.x->border_pixel = pix; + + if (s->display.x->window_desc != 0 && s->display.x->border_width > 0) + { + Pixmap temp; + int mask; + + BLOCK_INPUT; +#ifdef HAVE_X11 + XSetWindowBorder (x_current_display, s->display.x->window_desc, + pix); + if (s->display.x->h_scrollbar) + XSetWindowBorder (x_current_display, s->display.x->h_slider, + pix); + if (s->display.x->v_scrollbar) + XSetWindowBorder (x_current_display, s->display.x->v_slider, + pix); +#else + if (pix < 0) + temp = XMakePixmap ((Bitmap) XStoreBitmap (16, 16, gray_bits), + BLACK_PIX_DEFAULT, WHITE_PIX_DEFAULT); + else + temp = XMakeTile (pix); + XChangeBorder (s->display.x->window_desc, temp); + XFreePixmap (XDISPLAY temp); +#endif /* not HAVE_X11 */ + UNBLOCK_INPUT; + + if (s->visible) + redraw_screen (s); + } +} + +void +x_set_icon_type (s, arg, oldval) + struct screen *s; + Lisp_Object arg, oldval; +{ + Lisp_Object tem; + int result; + + if (EQ (oldval, Qnil) == EQ (arg, Qnil)) + return; + + BLOCK_INPUT; + if (NULL (arg)) + result = x_text_icon (s, 0); + else + result = x_bitmap_icon (s, 0); + + if (result) + { + error ("No icon window available."); + UNBLOCK_INPUT; + } + + /* If the window was unmapped (and its icon was mapped), + the new icon is not mapped, so map the window in its stead. */ + if (s->visible) + XMapWindow (XDISPLAY s->display.x->window_desc); + + XFlushQueue (); + UNBLOCK_INPUT; +} + +void +x_set_font (s, arg, oldval) + struct screen *s; + Lisp_Object arg, oldval; +{ + unsigned char *name; + int result; + + CHECK_STRING (arg, 1); + name = XSTRING (arg)->data; + + BLOCK_INPUT; + result = x_new_font (s, name); + UNBLOCK_INPUT; + + if (result) + error ("Font \"%s\" is not defined", name); +} + +void +x_set_border_width (s, arg, oldval) + struct screen *s; + Lisp_Object arg, oldval; +{ + CHECK_NUMBER (arg, 0); + + if (XINT (arg) == s->display.x->border_width) + return; + + if (s->display.x->window_desc != 0) + error ("Cannot change the border width of a window"); + + s->display.x->border_width = XINT (arg); +} + +void +x_set_internal_border_width (s, arg, oldval) + struct screen *s; + Lisp_Object arg, oldval; +{ + int mask; + int old = s->display.x->internal_border_width; + + CHECK_NUMBER (arg, 0); + s->display.x->internal_border_width = XINT (arg); + if (s->display.x->internal_border_width < 0) + s->display.x->internal_border_width = 0; + + if (s->display.x->internal_border_width == old) + return; + + if (s->display.x->window_desc != 0) + { + BLOCK_INPUT; + x_set_window_size (s, s->width, s->height); +#if 0 + x_set_resize_hint (s); +#endif + XFlushQueue (); + UNBLOCK_INPUT; + SET_SCREEN_GARBAGED (s); + } +} + +void +x_set_name (s, arg, oldval) + struct screen *s; + Lisp_Object arg, oldval; +{ + CHECK_STRING (arg, 0); + + if (s->display.x->window_desc) + { + s->name = arg; + BLOCK_INPUT; + XStoreName (XDISPLAY s->display.x->window_desc, + (char *) XSTRING (arg)->data); + XSetIconName (XDISPLAY s->display.x->window_desc, + (char *) XSTRING (arg)->data); + UNBLOCK_INPUT; + } +} + +void +x_set_autoraise (s, arg, oldval) + struct screen *s; + Lisp_Object arg, oldval; +{ + s->auto_raise = !EQ (Qnil, arg); +} + +void +x_set_autolower (s, arg, oldval) + struct screen *s; + Lisp_Object arg, oldval; +{ + s->auto_lower = !EQ (Qnil, arg); +} + +#ifdef HAVE_X11 +int n_faces; + +x_set_face (scr, font, background, foreground, stipple) + struct screen *scr; + XFontStruct *font; + unsigned long background, foreground; + Pixmap stipple; +{ + XGCValues gc_values; + GC temp_gc; + unsigned long gc_mask; + struct face *new_face; + unsigned int width = 16; + unsigned int height = 16; + + if (n_faces == MAX_FACES_AND_GLYPHS) + return 1; + + /* Create the Graphics Context. */ + gc_values.font = font->fid; + gc_values.foreground = foreground; + gc_values.background = background; + gc_values.line_width = 0; + gc_mask = GCLineWidth | GCFont | GCForeground | GCBackground; + if (stipple) + { + gc_values.stipple + = XCreateBitmapFromData (x_current_display, ROOT_WINDOW, + (char *) stipple, width, height); + gc_mask |= GCStipple; + } + + temp_gc = XCreateGC (x_current_display, scr->display.x->window_desc, + gc_mask, &gc_values); + if (!temp_gc) + return 1; + new_face = (struct face *) xmalloc (sizeof (struct face)); + if (!new_face) + { + XFreeGC (x_current_display, temp_gc); + return 1; + } + + new_face->font = font; + new_face->foreground = foreground; + new_face->background = background; + new_face->face_gc = temp_gc; + if (stipple) + new_face->stipple = gc_values.stipple; + + x_face_table[++n_faces] = new_face; + return 1; +} + +x_set_glyph (scr, glyph) +{ +} + +#if 0 +DEFUN ("x-set-face-font", Fx_set_face_font, Sx_set_face_font, 4, 2, 0, + "Specify face table entry FACE-CODE to be the font named by FONT,\n\ + in colors FOREGROUND and BACKGROUND.") + (face_code, font_name, foreground, background) + Lisp_Object face_code; + Lisp_Object font_name; + Lisp_Object foreground; + Lisp_Object background; +{ + register struct face *fp; /* Current face info. */ + register int fn; /* Face number. */ + register FONT_TYPE *f; /* Font data structure. */ + unsigned char *newname; + int fg, bg; + GC temp_gc; + XGCValues gc_values; + + /* Need to do something about this. */ + Drawable drawable = selected_screen->display.x->window_desc; + + CHECK_NUMBER (face_code, 1); + CHECK_STRING (font_name, 2); + + if (EQ (foreground, Qnil) || EQ (background, Qnil)) + { + fg = selected_screen->display.x->foreground_pixel; + bg = selected_screen->display.x->background_pixel; + } + else + { + CHECK_NUMBER (foreground, 0); + CHECK_NUMBER (background, 1); + + fg = x_decode_color (XINT (foreground), BLACK_PIX_DEFAULT); + bg = x_decode_color (XINT (background), WHITE_PIX_DEFAULT); + } + + fn = XINT (face_code); + if ((fn < 1) || (fn > 255)) + error ("Invalid face code, %d", fn); + + newname = XSTRING (font_name)->data; + BLOCK_INPUT; + f = (*newname == 0 ? 0 : XGetFont (newname)); + UNBLOCK_INPUT; + if (f == 0) + error ("Font \"%s\" is not defined", newname); + + fp = x_face_table[fn]; + if (fp == 0) + { + x_face_table[fn] = fp = (struct face *) xmalloc (sizeof (struct face)); + bzero (fp, sizeof (struct face)); + fp->face_type = x_pixmap; + } + else if (FACE_IS_FONT (fn)) + { + BLOCK_INPUT; + XFreeGC (FACE_FONT (fn)); + UNBLOCK_INPUT; + } + else if (FACE_IS_IMAGE (fn)) /* This should not happen... */ + { + BLOCK_INPUT; + XFreePixmap (x_current_display, FACE_IMAGE (fn)); + fp->face_type = x_font; + UNBLOCK_INPUT; + } + else + abort (); + + fp->face_GLYPH.font_desc.font = f; + gc_values.font = f->fid; + gc_values.foreground = fg; + gc_values.background = bg; + fp->face_GLYPH.font_desc.face_gc = XCreateGC (x_current_display, + drawable, GCFont | GCForeground + | GCBackground, &gc_values); + fp->face_GLYPH.font_desc.font_width = FONT_WIDTH (f); + fp->face_GLYPH.font_desc.font_height = FONT_HEIGHT (f); + + return face_code; +} +#endif +#else /* X10 */ +DEFUN ("x-set-face", Fx_set_face, Sx_set_face, 4, 4, 0, + "Specify face table entry FACE-CODE to be the font named by FONT,\n\ + in colors FOREGROUND and BACKGROUND.") + (face_code, font_name, foreground, background) + Lisp_Object face_code; + Lisp_Object font_name; + Lisp_Object foreground; + Lisp_Object background; +{ + register struct face *fp; /* Current face info. */ + register int fn; /* Face number. */ + register FONT_TYPE *f; /* Font data structure. */ + unsigned char *newname; + + CHECK_NUMBER (face_code, 1); + CHECK_STRING (font_name, 2); + + fn = XINT (face_code); + if ((fn < 1) || (fn > 255)) + error ("Invalid face code, %d", fn); + + /* Ask the server to find the specified font. */ + newname = XSTRING (font_name)->data; + BLOCK_INPUT; + f = (*newname == 0 ? 0 : XGetFont (newname)); + UNBLOCK_INPUT; + if (f == 0) + error ("Font \"%s\" is not defined", newname); + + /* Get the face structure for face_code in the face table. + Make sure it exists. */ + fp = x_face_table[fn]; + if (fp == 0) + { + x_face_table[fn] = fp = (struct face *) xmalloc (sizeof (struct face)); + bzero (fp, sizeof (struct face)); + } + + /* If this face code already exists, get rid of the old font. */ + if (fp->font != 0 && fp->font != f) + { + BLOCK_INPUT; + XLoseFont (fp->font); + UNBLOCK_INPUT; + } + + /* Store the specified information in FP. */ + fp->fg = x_decode_color (foreground, BLACK_PIX_DEFAULT); + fp->bg = x_decode_color (background, WHITE_PIX_DEFAULT); + fp->font = f; + + return face_code; +} +#endif /* X10 */ + +#if 0 +/* This is excluded because there is no painless way + to get or to remember the name of the font. */ + +DEFUN ("x-get-face", Fx_get_face, Sx_get_face, 1, 1, 0, + "Get data defining face code FACE. FACE is an integer.\n\ +The value is a list (FONT FG-COLOR BG-COLOR).") + (face) + Lisp_Object face; +{ + register struct face *fp; /* Current face info. */ + register int fn; /* Face number. */ + + CHECK_NUMBER (face, 1); + fn = XINT (face); + if ((fn < 1) || (fn > 255)) + error ("Invalid face code, %d", fn); + + /* Make sure the face table exists and this face code is defined. */ + if (x_face_table == 0 || x_face_table[fn] == 0) + return Qnil; + + fp = x_face_table[fn]; + + return Fcons (build_string (fp->name), + Fcons (make_number (fp->fg), + Fcons (make_number (fp->bg), Qnil))); +} +#endif /* 0 */ + +/* Subroutines of creating an X screen. */ + +#ifdef HAVE_X11 +extern char *x_get_string_resource (); +extern XrmDatabase x_load_resources (); + +DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 1, 3, 0, + "Retrieve the value of ATTRIBUTE from the X defaults database. This\n\ +searches using a key of the form \"INSTANCE.ATTRIBUTE\", with class\n\ +\"Emacs\", where INSTANCE is the name under which Emacs was invoked.\n\ +\n\ +Optional arguments COMPONENT and CLASS specify the component for which\n\ +we should look up ATTRIBUTE. When specified, Emacs searches using a\n\ +key of the form INSTANCE.COMPONENT.ATTRIBUTE, with class \"Emacs.CLASS\".") + (attribute, name, class) + Lisp_Object attribute, name, class; +{ + register char *value; + char *name_key; + char *class_key; + + CHECK_STRING (attribute, 0); + if (!NULL (name)) + CHECK_STRING (name, 1); + if (!NULL (class)) + CHECK_STRING (class, 2); + if (NULL (name) != NULL (class)) + error ("x-get-resource: must specify both NAME and CLASS or neither"); + + name_key = (char *) alloca (XSTRING (invocation_name)->size + 1 + + (NULL (name) ? 0 : XSTRING (name)->size + 1) + + XSTRING (attribute)->size + 1); + + if (NULL (name)) + { + sprintf (name_key, "%s.%s", + XSTRING (invocation_name)->data, + XSTRING (attribute)->data); + class_key = EMACS_CLASS; + } + else + { + class_key = (char *) alloca (sizeof (EMACS_CLASS) + + XSTRING (class)->size + 1); + + sprintf (name_key, "%s.%s.%s", + XSTRING (invocation_name)->data, + XSTRING (name)->data, + XSTRING (attribute)->data); + sprintf (class_key, "%s.%s", + XSTRING (invocation_name)->data, + XSTRING (class)->data); + } + + value = x_get_string_resource (xrdb, name_key, class_key); + + if (value != (char *) 0) + return build_string (value); + else + return Qnil; +} + +#else /* X10 */ + +DEFUN ("x-get-default", Fx_get_default, Sx_get_default, 1, 2, 0, + "Get X default ATTRIBUTE from the system, or nil if no default.\n\ +Value is a string (when not nil) and ATTRIBUTE is also a string.\n\ +The defaults are specified in the file `~/.Xdefaults'.") + (arg, name) + Lisp_Object arg, name; +{ + register unsigned char *value; + + CHECK_STRING (arg, 1); + + value = (unsigned char *) XGetDefault (XDISPLAY + XSTRING (invocation_name)->data, + XSTRING (arg)->data); + if (value == 0) + /* Try reversing last two args, in case this is the buggy version of X. */ + value = (unsigned char *) XGetDefault (XDISPLAY + XSTRING (arg)->data, + XSTRING (invocation_name)->data); + if (value != 0) + return build_string (value); + else + return (Qnil); +} + +#define Fx_get_resource Fx_get_default + +#endif /* X10 */ + +/* Return the value of parameter PARAM. + First search ALIST, then the X defaults database. + If XPROPNAME starts with `#', convert the X default to an integer; + otherwise, to a string. + If no X-default is specified, return nil. */ + +static Lisp_Object +x_get_arg (alist, param, screen_name, xpropname) + Lisp_Object alist, param, screen_name; + char *xpropname; +{ + register Lisp_Object tem; + + tem = Fassq (param, alist); + if (EQ (tem, Qnil)) + tem = Fassq (param, Vdefault_screen_alist); + if (EQ (tem, Qnil)) + { + if (xpropname == 0) + return tem; + + if (*xpropname == '#') + { + tem = Fx_get_resource (build_string (xpropname + 1), + screen_name, SCREEN_CLASS); + if (EQ (tem, Qnil)) + return Qnil; + return make_number (atoi (XSTRING (tem)->data)); + } + + if (*xpropname == '?') + { + tem = Fx_get_resource (build_string (xpropname + 1), + screen_name, SCREEN_CLASS); + if (XTYPE (tem) == Lisp_String) + { + tem = Fdowncase (tem); + if (!strcmp (XSTRING (tem)->data, "on") + || !strcmp (XSTRING (tem)->data, "true")) + return Qt; + } + return Qnil; + } + + return Fx_get_resource (build_string (xpropname), + screen_name, SCREEN_CLASS); + } + return Fcdr (tem); +} + +/* Record in screen S the specified or default value according to ALIST + of the parameter named PARAM (a Lisp symbol). + If no value is specified for PARAM, look for an X default for XPROP + on the screen named NAME. + If that is not found either, use the value DEFLT. */ + +static Lisp_Object +x_default_parameter (s, alist, propname, deflt, xprop) + struct screen *s; + Lisp_Object alist; + char *propname; + Lisp_Object deflt; + char *xprop; +{ + Lisp_Object propsym = intern (propname); + Lisp_Object tem; + + tem = x_get_arg (alist, propsym, s->name, xprop); + if (EQ (tem, Qnil)) + tem = deflt; + store_screen_param (s, propsym, tem); + x_set_screen_param (s, propsym, tem, Qnil); + return tem; +} + +DEFUN ("x-geometry", Fx_geometry, Sx_geometry, 1, 1, 0, + "Parse an X-style geometry string STRING.\n\ +Returns an alist of the form ((top . TOP), (left . LEFT) ... ).") + (string) +{ + int geometry, x, y; + unsigned int width, height; + Lisp_Object values[4]; + + CHECK_STRING (string, 0); + + geometry = XParseGeometry ((char *) XSTRING (string)->data, + &x, &y, &width, &height); + + switch (geometry & 0xf) /* Mask out {X,Y}Negative */ + { + case (XValue | YValue): + /* What's one pixel among friends? + Perhaps fix this some day by returning symbol `extreme-top'... */ + if (x == 0 && (geometry & XNegative)) + x = -1; + if (y == 0 && (geometry & YNegative)) + y = -1; + values[0] = Fcons (intern ("left"), make_number (x)); + values[1] = Fcons (intern ("top"), make_number (y)); + return Flist (2, values); + break; + + case (WidthValue | HeightValue): + values[0] = Fcons (intern ("width"), make_number (width)); + values[1] = Fcons (intern ("height"), make_number (height)); + return Flist (2, values); + break; + + case (XValue | YValue | WidthValue | HeightValue): + if (x == 0 && (geometry & XNegative)) + x = -1; + if (y == 0 && (geometry & YNegative)) + y = -1; + values[0] = Fcons (intern ("width"), make_number (width)); + values[1] = Fcons (intern ("height"), make_number (height)); + values[2] = Fcons (intern ("left"), make_number (x)); + values[3] = Fcons (intern ("top"), make_number (y)); + return Flist (4, values); + break; + + case 0: + return Qnil; + + default: + error ("Must specify x and y value, and/or width and height"); + } +} + +#ifdef HAVE_X11 +/* Calculate the desired size and position of this window, + or set rubber-band prompting if none. */ + +#define DEFAULT_ROWS 40 +#define DEFAULT_COLS 80 + +static +x_figure_window_size (s, parms) + struct screen *s; + Lisp_Object parms; +{ + register Lisp_Object tem0, tem1; + int height, width, left, top; + register int geometry; + long window_prompting = 0; + + /* Default values if we fall through. + Actually, if that happens we should get + window manager prompting. */ + s->width = DEFAULT_COLS; + s->height = DEFAULT_ROWS; + s->display.x->top_pos = 1; + s->display.x->left_pos = 1; + + tem0 = x_get_arg (parms, intern ("height"), s->name, 0); + tem1 = x_get_arg (parms, intern ("width"), s->name, 0); + if (! EQ (tem0, Qnil) && ! EQ (tem1, Qnil)) + { + CHECK_NUMBER (tem0, 0); + CHECK_NUMBER (tem1, 0); + s->height = XINT (tem0); + s->width = XINT (tem1); + window_prompting |= USSize; + } + else if (! EQ (tem0, Qnil) || ! EQ (tem1, Qnil)) + error ("Must specify *both* height and width"); + + s->display.x->pixel_width = (FONT_WIDTH (s->display.x->font) * s->width + + 2 * s->display.x->internal_border_width); + s->display.x->pixel_height = (FONT_HEIGHT (s->display.x->font) * s->height + + 2 * s->display.x->internal_border_width); + + tem0 = x_get_arg (parms, intern ("top"), s->name, 0); + tem1 = x_get_arg (parms, intern ("left"), s->name, 0); + if (! EQ (tem0, Qnil) && ! EQ (tem1, Qnil)) + { + CHECK_NUMBER (tem0, 0); + CHECK_NUMBER (tem1, 0); + s->display.x->top_pos = XINT (tem0); + s->display.x->left_pos = XINT (tem1); + x_calc_absolute_position (s); + window_prompting |= USPosition; + } + else if (! EQ (tem0, Qnil) || ! EQ (tem1, Qnil)) + error ("Must specify *both* top and left corners"); + + switch (window_prompting) + { + case USSize | USPosition: + return window_prompting; + break; + + case USSize: /* Got the size, need the position. */ + window_prompting |= PPosition; + return window_prompting; + break; + + case USPosition: /* Got the position, need the size. */ + window_prompting |= PSize; + return window_prompting; + break; + + case 0: /* Got nothing, take both from geometry. */ + window_prompting |= PPosition | PSize; + return window_prompting; + break; + + default: + /* Somehow a bit got set in window_prompting that we didn't + put there. */ + abort (); + } +} + +static void +x_window (s) + struct screen *s; +{ + XSetWindowAttributes attributes; + unsigned long attribute_mask; + XClassHint class_hints; + + attributes.background_pixel = s->display.x->background_pixel; + attributes.border_pixel = s->display.x->border_pixel; + attributes.bit_gravity = StaticGravity; + attributes.backing_store = NotUseful; + attributes.save_under = True; + attributes.event_mask = STANDARD_EVENT_SET; + attribute_mask = (CWBackPixel | CWBorderPixel | CWBitGravity +#if 0 + | CWBackingStore | CWSaveUnder +#endif + | CWEventMask); + + BLOCK_INPUT; + s->display.x->window_desc + = XCreateWindow (x_current_display, ROOT_WINDOW, + s->display.x->left_pos, + s->display.x->top_pos, + PIXEL_WIDTH (s), PIXEL_HEIGHT (s), + s->display.x->border_width, + CopyFromParent, /* depth */ + InputOutput, /* class */ + screen_visual, /* set in Fx_open_connection */ + attribute_mask, &attributes); + + class_hints.res_name = id_name; + class_hints.res_class = EMACS_CLASS; + XSetClassHint (x_current_display, s->display.x->window_desc, &class_hints); + + XDefineCursor (XDISPLAY s->display.x->window_desc, + s->display.x->text_cursor); + UNBLOCK_INPUT; + + if (s->display.x->window_desc == 0) + error ("Unable to create window."); +} + +/* Handle the icon stuff for this window. Perhaps later we might + want an x_set_icon_position which can be called interactively as + well. */ + +static void +x_icon (s, parms) + struct screen *s; + Lisp_Object parms; +{ + register Lisp_Object tem0,tem1; + XWMHints hints; + + /* Set the position of the icon. Note that twm groups all + icons in an icon window. */ + tem0 = x_get_arg (parms, intern ("icon-left"), s->name, 0); + tem1 = x_get_arg (parms, intern ("icon-top"), s->name, 0); + if (!EQ (tem0, Qnil) && !EQ (tem1, Qnil)) + { + CHECK_NUMBER (tem0, 0); + CHECK_NUMBER (tem1, 0); + hints.icon_x = XINT (tem0); + hints.icon_x = XINT (tem0); + } + else if (!EQ (tem0, Qnil) || !EQ (tem1, Qnil)) + error ("Both left and top icon corners of icon must be specified"); + else + { + hints.icon_x = s->display.x->left_pos; + hints.icon_y = s->display.x->top_pos; + } + + /* Start up iconic or window? */ + tem0 = x_get_arg (parms, intern ("iconic-startup"), s->name, 0); + if (!EQ (tem0, Qnil)) + hints.initial_state = IconicState; + else + hints.initial_state = NormalState; /* the default, actually. */ + hints.input = False; + + BLOCK_INPUT; + hints.flags = StateHint | IconPositionHint | InputHint; + XSetWMHints (x_current_display, s->display.x->window_desc, &hints); + UNBLOCK_INPUT; +} + +/* Make the GC's needed for this window, setting the + background, border and mouse colors; also create the + mouse cursor and the gray border tile. */ + +static void +x_make_gc (s) + struct screen *s; +{ + XGCValues gc_values; + GC temp_gc; + XImage tileimage; + static char cursor_bits[] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + /* Create the GC's of this screen. + Note that many default values are used. */ + + /* Normal video */ + gc_values.font = s->display.x->font->fid; + gc_values.foreground = s->display.x->foreground_pixel; + gc_values.background = s->display.x->background_pixel; + gc_values.line_width = 0; /* Means 1 using fast algorithm. */ + s->display.x->normal_gc = XCreateGC (x_current_display, + s->display.x->window_desc, + GCLineWidth | GCFont + | GCForeground | GCBackground, + &gc_values); + + /* Reverse video style. */ + gc_values.foreground = s->display.x->background_pixel; + gc_values.background = s->display.x->foreground_pixel; + s->display.x->reverse_gc = XCreateGC (x_current_display, + s->display.x->window_desc, + GCFont | GCForeground | GCBackground + | GCLineWidth, + &gc_values); + + /* Cursor has cursor-color background, background-color foreground. */ + gc_values.foreground = s->display.x->background_pixel; + gc_values.background = s->display.x->cursor_pixel; + gc_values.fill_style = FillOpaqueStippled; + gc_values.stipple + = XCreateBitmapFromData (x_current_display, ROOT_WINDOW, + cursor_bits, 16, 16); + s->display.x->cursor_gc + = XCreateGC (x_current_display, s->display.x->window_desc, + (GCFont | GCForeground | GCBackground + | GCFillStyle | GCStipple | GCLineWidth), + &gc_values); + + /* Create the gray border tile used when the pointer is not in + the screen. Since this depends on the screen's pixel values, + this must be done on a per-screen basis. */ + s->display.x->border_tile = + XCreatePixmap (x_current_display, ROOT_WINDOW, 16, 16, + DefaultDepth (x_current_display, + XDefaultScreen (x_current_display))); + gc_values.foreground = s->display.x->foreground_pixel; + gc_values.background = s->display.x->background_pixel; + temp_gc = XCreateGC (x_current_display, + (Drawable) s->display.x->border_tile, + GCForeground | GCBackground, &gc_values); + + /* These are things that should be determined by the server, in + Fx_open_connection */ + tileimage.height = 16; + tileimage.width = 16; + tileimage.xoffset = 0; + tileimage.format = XYBitmap; + tileimage.data = gray_bits; + tileimage.byte_order = LSBFirst; + tileimage.bitmap_unit = 8; + tileimage.bitmap_bit_order = LSBFirst; + tileimage.bitmap_pad = 8; + tileimage.bytes_per_line = (16 + 7) >> 3; + tileimage.depth = 1; + XPutImage (x_current_display, s->display.x->border_tile, temp_gc, + &tileimage, 0, 0, 0, 0, 16, 16); + XFreeGC (x_current_display, temp_gc); +} +#endif /* HAVE_X11 */ + +DEFUN ("x-create-screen", Fx_create_screen, Sx_create_screen, + 1, 1, 0, + "Make a new X window, which is considered a \"screen\" in Emacs terms.\n\ +Return an Emacs screen object representing the X window.\n\ +ALIST is an alist of screen parameters.\n\ +The value of ``x-screen-defaults'' is an additional alist\n\ +of default parameters which apply when not overridden by ALIST.\n\ +If the parameters specify that the screen should not have a minibuffer,\n\ +then ``global-minibuffer-screen'' must be a screen whose minibuffer can\n\ +be shared by the new screen.") + (parms) + Lisp_Object parms; +{ +#ifdef HAVE_X11 + struct screen *s; + Lisp_Object screen, tem; + Lisp_Object name; + int minibuffer_only = 0; + long window_prompting = 0; + int width, height; + + if (x_current_display == 0) + error ("X windows are not in use or not initialized"); + + name = Fassq (intern ("name"), parms); + if (NULL (name)) + name = build_string (id_name); + else + { + if (XTYPE (name) != Lisp_Cons) + /* Fassq should always return nil or a cons! */ + abort (); + name = XCONS (name)->cdr; + if (XTYPE (name) != Lisp_String) + error ("x-create-screen: name parameter must be a string."); + } + + tem = x_get_arg (parms, intern ("minibuffer"), name, 0); + if (EQ (tem, intern ("none"))) + s = make_screen_without_minibuffer (Qnil); + else if (EQ (tem, intern ("only"))) + { + s = make_minibuffer_screen (); + minibuffer_only = 1; + } + else if (! EQ (tem, Qnil)) + s = make_screen_without_minibuffer (tem); + else + s = make_screen (1); + + /* Set the name; the functions to which we pass s expect the + name to be set. */ + XSET (s->name, Lisp_String, name); + + XSET (screen, Lisp_Screen, s); + s->output_method = output_x_window; + s->display.x = (struct x_display *) xmalloc (sizeof (struct x_display)); + bzero (s->display.x, sizeof (struct x_display)); + + /* Extract the window parameters from the supplied values + that are needed to determine window geometry. */ + x_default_parameter (s, parms, "font", + build_string ("9x15"), "font"); + x_default_parameter (s, parms, "background-color", + build_string ("white"), "background"); + x_default_parameter (s, parms, "border-width", + make_number (2), "#BorderWidth"); + x_default_parameter (s, parms, "internal-border-width", + make_number (4), "#InternalBorderWidth"); + + /* Also do the stuff which must be set before the window exists. */ + x_default_parameter (s, parms, "foreground-color", + build_string ("black"), "foreground"); + x_default_parameter (s, parms, "mouse-color", + build_string ("black"), "mouse"); + x_default_parameter (s, parms, "cursor-color", + build_string ("black"), "cursor"); + x_default_parameter (s, parms, "border-color", + build_string ("black"), "border"); + + /* Need to do icon type, auto-raise, auto-lower. */ + + s->display.x->parent_desc = ROOT_WINDOW; + window_prompting = x_figure_window_size (s, parms); + + x_window (s); + x_icon (s, parms); + x_make_gc (s); + + /* Dimensions, especially s->height, must be done via change_screen_size. + Change will not be effected unless different from the current + s->height. */ + width = s->width; + height = s->height; + s->height = s->width = 0; + change_screen_size (s, height, width, 1); + BLOCK_INPUT; + x_wm_set_size_hint (s, window_prompting); + UNBLOCK_INPUT; + + tem = x_get_arg (parms, intern ("unsplittable"), name, 0); + s->no_split = minibuffer_only || EQ (tem, Qt); + + /* Now handle the rest of the parameters. */ + x_default_parameter (s, parms, "name", + build_string (id_name), "Title"); + x_default_parameter (s, parms, "horizontal-scroll-bar", + Qnil, "?HScrollBar"); + x_default_parameter (s, parms, "vertical-scroll-bar", + Qnil, "?VScrollBar"); + + /* Make the window appear on the screen and enable display. */ + if (!EQ (x_get_arg (parms, intern ("suppress-initial-map"), name, 0), Qt)) + x_make_screen_visible (s); + + return screen; +#else /* X10 */ + struct screen *s; + Lisp_Object screen, tem; + Lisp_Object name; + int pixelwidth, pixelheight; + Cursor cursor; + int height, width; + Window parent; + Pixmap temp; + int minibuffer_only = 0; + Lisp_Object vscroll, hscroll; + + if (x_current_display == 0) + error ("X windows are not in use or not initialized"); + + name = Fassq (intern ("name"), parms); + + tem = x_get_arg (parms, intern ("minibuffer"), name, 0); + if (EQ (tem, intern ("none"))) + s = make_screen_without_minibuffer (Qnil); + else if (EQ (tem, intern ("only"))) + { + s = make_minibuffer_screen (); + minibuffer_only = 1; + } + else if (! EQ (tem, Qnil)) + s = make_screen_without_minibuffer (tem); + else + s = make_screen (1); + + parent = ROOT_WINDOW; + + XSET (screen, Lisp_Screen, s); + s->output_method = output_x_window; + s->display.x = (struct x_display *) xmalloc (sizeof (struct x_display)); + bzero (s->display.x, sizeof (struct x_display)); + + /* Some temprorary default values for height and width. */ + width = 80; + height = 40; + s->display.x->left_pos = -1; + s->display.x->top_pos = -1; + + /* Give the screen a default name (which may be overridden with PARMS). */ + + strncpy (iconidentity, ICONTAG, MAXICID); + if (gethostname (&iconidentity[sizeof (ICONTAG) - 1], + (MAXICID - 1) - sizeof (ICONTAG))) + iconidentity[sizeof (ICONTAG) - 2] = '\0'; + s->name = build_string (iconidentity); + + /* Extract some window parameters from the supplied values. + These are the parameters that affect window geometry. */ + + tem = x_get_arg (parms, intern ("font"), name, "BodyFont"); + if (EQ (tem, Qnil)) + tem = build_string ("9x15"); + x_set_font (s, tem); + x_default_parameter (s, parms, "border-color", + build_string ("black"), "Border"); + x_default_parameter (s, parms, "background-color", + build_string ("white"), "Background"); + x_default_parameter (s, parms, "foreground-color", + build_string ("black"), "Foreground"); + x_default_parameter (s, parms, "mouse-color", + build_string ("black"), "Mouse"); + x_default_parameter (s, parms, "cursor-color", + build_string ("black"), "Cursor"); + x_default_parameter (s, parms, "border-width", + make_number (2), "#BorderWidth"); + x_default_parameter (s, parms, "internal-border-width", + make_number (4), "#InternalBorderWidth"); + x_default_parameter (s, parms, "auto-raise", + Qnil, "?AutoRaise"); + + hscroll = x_get_arg (parms, intern ("horizontal-scroll-bar"), name, 0); + vscroll = x_get_arg (parms, intern ("vertical-scroll-bar"), name, 0); + + if (s->display.x->internal_border_width < 0) + s->display.x->internal_border_width = 0; + + tem = x_get_arg (parms, intern ("window-id"), name, 0); + if (!EQ (tem, Qnil)) + { + WINDOWINFO_TYPE wininfo; + int nchildren; + Window *children, root; + + CHECK_STRING (tem, 0); + s->display.x->window_desc = (Window) atoi (XSTRING (tem)->data); + + BLOCK_INPUT; + XGetWindowInfo (s->display.x->window_desc, &wininfo); + XQueryTree (s->display.x->window_desc, &parent, &nchildren, &children); + free (children); + UNBLOCK_INPUT; + + height = (wininfo.height - 2 * s->display.x->internal_border_width) + / FONT_HEIGHT (s->display.x->font); + width = (wininfo.width - 2 * s->display.x->internal_border_width) + / FONT_WIDTH (s->display.x->font); + s->display.x->left_pos = wininfo.x; + s->display.x->top_pos = wininfo.y; + s->visible = wininfo.mapped != 0; + s->display.x->border_width = wininfo.bdrwidth; + s->display.x->parent_desc = parent; + } + else + { + tem = x_get_arg (parms, intern ("parent-id"), name, 0); + if (!EQ (tem, Qnil)) + { + CHECK_STRING (tem, 0); + parent = (Window) atoi (XSTRING (tem)->data); + } + s->display.x->parent_desc = parent; + tem = x_get_arg (parms, intern ("height"), name, 0); + if (EQ (tem, Qnil)) + { + tem = x_get_arg (parms, intern ("width"), name, 0); + if (EQ (tem, Qnil)) + { + tem = x_get_arg (parms, intern ("top"), name, 0); + if (EQ (tem, Qnil)) + tem = x_get_arg (parms, intern ("left"), name, 0); + } + } + /* Now TEM is nil if no edge or size was specified. + In that case, we must do rubber-banding. */ + if (EQ (tem, Qnil)) + { + tem = x_get_arg (parms, intern ("geometry"), name, 0); + x_rubber_band (s, + &s->display.x->left_pos, &s->display.x->top_pos, + &width, &height, + (XTYPE (tem) == Lisp_String + ? (char *) XSTRING (tem)->data : ""), + XSTRING (s->name)->data, + !NULL (hscroll), !NULL (vscroll)); + } + else + { + /* Here if at least one edge or size was specified. + Demand that they all were specified, and use them. */ + tem = x_get_arg (parms, intern ("height"), name, 0); + if (EQ (tem, Qnil)) + error ("Height not specified"); + CHECK_NUMBER (tem, 0); + height = XINT (tem); + + tem = x_get_arg (parms, intern ("width"), name, 0); + if (EQ (tem, Qnil)) + error ("Width not specified"); + CHECK_NUMBER (tem, 0); + width = XINT (tem); + + tem = x_get_arg (parms, intern ("top"), name, 0); + if (EQ (tem, Qnil)) + error ("Top position not specified"); + CHECK_NUMBER (tem, 0); + s->display.x->left_pos = XINT (tem); + + tem = x_get_arg (parms, intern ("left"), name, 0); + if (EQ (tem, Qnil)) + error ("Left position not specified"); + CHECK_NUMBER (tem, 0); + s->display.x->top_pos = XINT (tem); + } + + pixelwidth = (width * FONT_WIDTH (s->display.x->font) + + 2 * s->display.x->internal_border_width + + (!NULL (vscroll) ? VSCROLL_WIDTH : 0)); + pixelheight = (height * FONT_HEIGHT (s->display.x->font) + + 2 * s->display.x->internal_border_width + + (!NULL (hscroll) ? HSCROLL_HEIGHT : 0)); + + BLOCK_INPUT; + s->display.x->window_desc + = XCreateWindow (parent, + s->display.x->left_pos, /* Absolute horizontal offset */ + s->display.x->top_pos, /* Absolute Vertical offset */ + pixelwidth, pixelheight, + s->display.x->border_width, + BLACK_PIX_DEFAULT, WHITE_PIX_DEFAULT); + UNBLOCK_INPUT; + if (s->display.x->window_desc == 0) + error ("Unable to create window."); + } + + /* Install the now determined height and width + in the windows and in phys_lines and desired_lines. */ + /* ??? jla version had 1 here instead of 0. */ + change_screen_size (s, height, width, 1); + XSelectInput (s->display.x->window_desc, KeyPressed | ExposeWindow + | ButtonPressed | ButtonReleased | ExposeRegion | ExposeCopy + | EnterWindow | LeaveWindow | UnmapWindow ); + x_set_resize_hint (s); + + /* Tell the server the window's default name. */ + + XStoreName (XDISPLAY s->display.x->window_desc, XSTRING (s->name)->data); + /* Now override the defaults with all the rest of the specified + parms. */ + tem = x_get_arg (parms, intern ("unsplittable"), name, 0); + s->no_split = minibuffer_only || EQ (tem, Qt); + + /* Do not create an icon window if the caller says not to */ + if (!EQ (x_get_arg (parms, intern ("suppress-icon"), name, 0), Qt) + || s->display.x->parent_desc != ROOT_WINDOW) + { + x_text_icon (s, iconidentity); + x_default_parameter (s, parms, "icon-type", Qnil, "?BitmapIcon"); + } + + /* Tell the X server the previously set values of the + background, border and mouse colors; also create the mouse cursor. */ + BLOCK_INPUT; + temp = XMakeTile (s->display.x->background_pixel); + XChangeBackground (s->display.x->window_desc, temp); + XFreePixmap (temp); + UNBLOCK_INPUT; + x_set_border_pixel (s, s->display.x->border_pixel); + + x_set_mouse_color (s, Qnil, Qnil); + + /* Now override the defaults with all the rest of the specified parms. */ + + Fmodify_screen_parameters (screen, parms); + + if (!NULL (vscroll)) + install_vertical_scrollbar (s, pixelwidth, pixelheight); + if (!NULL (hscroll)) + install_horizontal_scrollbar (s, pixelwidth, pixelheight); + + /* Make the window appear on the screen and enable display. */ + + if (!EQ (x_get_arg (parms, intern ("suppress-initial-map"), name, 0), Qt)) + x_make_window_visible (s); + SCREEN_GARBAGED (s); + + return screen; +#endif /* X10 */ +} + +DEFUN ("focus-screen", Ffocus_screen, Sfocus_screen, 1, 1, 0, + "Set the focus on SCREEN.") + (screen) + Lisp_Object screen; +{ + CHECK_SCREEN (screen, 0); + + if (SCREEN_IS_X (XSCREEN (screen))) + { + BLOCK_INPUT; + x_focus_on_screen (XSCREEN (screen)); + UNBLOCK_INPUT; + return screen; + } + + return Qnil; +} + +DEFUN ("unfocus-screen", Funfocus_screen, Sunfocus_screen, 0, 0, 0, + "If a screen has been focused, release it.") + () +{ + if (x_focus_screen) + { + BLOCK_INPUT; + x_unfocus_screen (x_focus_screen); + UNBLOCK_INPUT; + } + + return Qnil; +} + +#ifndef HAVE_X11 +/* Computes an X-window size and position either from geometry GEO + or with the mouse. + + S is a screen. It specifies an X window which is used to + determine which display to compute for. Its font, borders + and colors control how the rectangle will be displayed. + + X and Y are where to store the positions chosen. + WIDTH and HEIGHT are where to store the sizes chosen. + + GEO is the geometry that may specify some of the info. + STR is a prompt to display. + HSCROLL and VSCROLL say whether we have horiz and vert scroll bars. */ + +int +x_rubber_band (s, x, y, width, height, geo, str, hscroll, vscroll) + struct screen *s; + int *x, *y, *width, *height; + char *geo; + char *str; + int hscroll, vscroll; +{ + OpaqueFrame frame; + Window tempwindow; + WindowInfo wininfo; + int border_color; + int background_color; + Lisp_Object tem; + int mask; + + BLOCK_INPUT; + + background_color = s->display.x->background_pixel; + border_color = s->display.x->border_pixel; + + frame.bdrwidth = s->display.x->border_width; + frame.border = XMakeTile (border_color); + frame.background = XMakeTile (background_color); + tempwindow = XCreateTerm (str, "emacs", geo, default_window, &frame, 10, 5, + (2 * s->display.x->internal_border_width + + (vscroll ? VSCROLL_WIDTH : 0)), + (2 * s->display.x->internal_border_width + + (hscroll ? HSCROLL_HEIGHT : 0)), + width, height, s->display.x->font, + FONT_WIDTH (s->display.x->font), + FONT_HEIGHT (s->display.x->font)); + XFreePixmap (frame.border); + XFreePixmap (frame.background); + + if (tempwindow != 0) + { + XQueryWindow (tempwindow, &wininfo); + XDestroyWindow (tempwindow); + *x = wininfo.x; + *y = wininfo.y; + } + + /* Coordinates we got are relative to the root window. + Convert them to coordinates relative to desired parent window + by scanning from there up to the root. */ + tempwindow = s->display.x->parent_desc; + while (tempwindow != ROOT_WINDOW) + { + int nchildren; + Window *children; + XQueryWindow (tempwindow, &wininfo); + *x -= wininfo.x; + *y -= wininfo.y; + XQueryTree (tempwindow, &tempwindow, &nchildren, &children); + free (children); + } + + UNBLOCK_INPUT; + return tempwindow != 0; +} +#endif /* not HAVE_X11 */ + +/* Set whether screen S has a horizontal scroll bar. + VAL is t or nil to specify it. */ + +static void +x_set_horizontal_scrollbar (s, val, oldval) + struct screen *s; + Lisp_Object val, oldval; +{ + if (!NULL (val)) + { + if (s->display.x->window_desc != 0) + { + BLOCK_INPUT; + s->display.x->h_scrollbar_height = HSCROLL_HEIGHT; + x_set_window_size (s, s->width, s->height); + install_horizontal_scrollbar (s); + SET_SCREEN_GARBAGED (s); + UNBLOCK_INPUT; + } + } + else + if (s->display.x->h_scrollbar) + { + BLOCK_INPUT; + s->display.x->h_scrollbar_height = 0; + XDestroyWindow (XDISPLAY s->display.x->h_scrollbar); + s->display.x->h_scrollbar = 0; + x_set_window_size (s, s->width, s->height); + s->garbaged++; + screen_garbaged++; + BLOCK_INPUT; + } +} + +/* Set whether screen S has a vertical scroll bar. + VAL is t or nil to specify it. */ + +static void +x_set_vertical_scrollbar (s, val, oldval) + struct screen *s; + Lisp_Object val, oldval; +{ + if (!NULL (val)) + { + if (s->display.x->window_desc != 0) + { + BLOCK_INPUT; + s->display.x->v_scrollbar_width = VSCROLL_WIDTH; + x_set_window_size (s, s->width, s->height); + install_vertical_scrollbar (s); + SET_SCREEN_GARBAGED (s); + UNBLOCK_INPUT; + } + } + else + if (s->display.x->v_scrollbar != 0) + { + BLOCK_INPUT; + s->display.x->v_scrollbar_width = 0; + XDestroyWindow (XDISPLAY s->display.x->v_scrollbar); + s->display.x->v_scrollbar = 0; + x_set_window_size (s, s->width, s->height); + SET_SCREEN_GARBAGED (s); + UNBLOCK_INPUT; + } +} + +/* Create the X windows for a vertical scroll bar + for a screen X that already has an X window but no scroll bar. */ + +static void +install_vertical_scrollbar (s) + struct screen *s; +{ + int ibw = s->display.x->internal_border_width; + Window parent; + XColor fore_color, back_color; + Pixmap up_arrow_pixmap, down_arrow_pixmap, slider_pixmap; + int pix_x, pix_y, width, height, border; + + height = s->display.x->pixel_height - ibw - 2; + width = VSCROLL_WIDTH - 2; + pix_x = s->display.x->pixel_width - ibw/2; + pix_y = ibw / 2; + border = 1; + +#ifdef HAVE_X11 + up_arrow_pixmap = + XCreatePixmapFromBitmapData (x_current_display, s->display.x->window_desc, + up_arrow_bits, 16, 16, + s->display.x->foreground_pixel, + s->display.x->background_pixel, + DefaultDepth (x_current_display, + XDefaultScreen (x_current_display))); + + down_arrow_pixmap = + XCreatePixmapFromBitmapData (x_current_display, s->display.x->window_desc, + down_arrow_bits, 16, 16, + s->display.x->foreground_pixel, + s->display.x->background_pixel, + DefaultDepth (x_current_display, + XDefaultScreen (x_current_display))); + + slider_pixmap = + XCreatePixmapFromBitmapData (x_current_display, s->display.x->window_desc, + gray_bits, 16, 16, + s->display.x->foreground_pixel, + s->display.x->background_pixel, + DefaultDepth (x_current_display, + XDefaultScreen (x_current_display))); + + /* These cursor shapes will be installed when the mouse enters + the appropriate window. */ + + up_arrow_cursor = XCreateFontCursor (x_current_display, XC_sb_up_arrow); + down_arrow_cursor = XCreateFontCursor (x_current_display, XC_sb_down_arrow); + v_double_arrow_cursor = XCreateFontCursor (x_current_display, XC_sb_v_double_arrow); + + s->display.x->v_scrollbar = + XCreateSimpleWindow (x_current_display, s->display.x->window_desc, + pix_x, pix_y, width, height, border, + s->display.x->foreground_pixel, + s->display.x->background_pixel); + XFlush (x_current_display); + XDefineCursor (x_current_display, s->display.x->v_scrollbar, + v_double_arrow_cursor); + + /* Create slider window */ + s->display.x->v_slider = + XCreateSimpleWindow (x_current_display, s->display.x->v_scrollbar, + 0, VSCROLL_WIDTH - 2, + VSCROLL_WIDTH - 4, VSCROLL_WIDTH - 4, + 1, s->display.x->border_pixel, + s->display.x->foreground_pixel); + XFlush (x_current_display); + XDefineCursor (x_current_display, s->display.x->v_slider, + v_double_arrow_cursor); + XSetWindowBackgroundPixmap (x_current_display, s->display.x->v_slider, + slider_pixmap); + + s->display.x->v_thumbup = + XCreateSimpleWindow (x_current_display, s->display.x->v_scrollbar, + 0, 0, + VSCROLL_WIDTH - 2, VSCROLL_WIDTH - 2, + 0, s->display.x->foreground_pixel, + s->display.x-> background_pixel); + XFlush (x_current_display); + XDefineCursor (x_current_display, s->display.x->v_thumbup, + up_arrow_cursor); + XSetWindowBackgroundPixmap (x_current_display, s->display.x->v_thumbup, + up_arrow_pixmap); + + s->display.x->v_thumbdown = + XCreateSimpleWindow (x_current_display, s->display.x->v_scrollbar, + 0, height - VSCROLL_WIDTH + 2, + VSCROLL_WIDTH - 2, VSCROLL_WIDTH - 2, + 0, s->display.x->foreground_pixel, + s->display.x->background_pixel); + XFlush (x_current_display); + XDefineCursor (x_current_display, s->display.x->v_thumbdown, + down_arrow_cursor); + XSetWindowBackgroundPixmap (x_current_display, s->display.x->v_thumbdown, + down_arrow_pixmap); + + fore_color.pixel = s->display.x->mouse_pixel; + back_color.pixel = s->display.x->background_pixel; + XQueryColor (x_current_display, + DefaultColormap (x_current_display, + DefaultScreen (x_current_display)), + &fore_color); + XQueryColor (x_current_display, + DefaultColormap (x_current_display, + DefaultScreen (x_current_display)), + &back_color); + XRecolorCursor (x_current_display, up_arrow_cursor, + &fore_color, &back_color); + XRecolorCursor (x_current_display, down_arrow_cursor, + &fore_color, &back_color); + XRecolorCursor (x_current_display, v_double_arrow_cursor, + &fore_color, &back_color); + + XFreePixmap (x_current_display, slider_pixmap); + XFreePixmap (x_current_display, up_arrow_pixmap); + XFreePixmap (x_current_display, down_arrow_pixmap); + XFlush (x_current_display); + + XSelectInput (x_current_display, s->display.x->v_scrollbar, + ButtonPressMask | ButtonReleaseMask + | PointerMotionMask | PointerMotionHintMask + | EnterWindowMask); + XSelectInput (x_current_display, s->display.x->v_slider, + ButtonPressMask | ButtonReleaseMask); + XSelectInput (x_current_display, s->display.x->v_thumbdown, + ButtonPressMask | ButtonReleaseMask); + XSelectInput (x_current_display, s->display.x->v_thumbup, + ButtonPressMask | ButtonReleaseMask); + XFlush (x_current_display); + + /* This should be done at the same time as the main window. */ + XMapWindow (x_current_display, s->display.x->v_scrollbar); + XMapSubwindows (x_current_display, s->display.x->v_scrollbar); + XFlush (x_current_display); +#else /* not HAVE_X11 */ + Bitmap b; + Pixmap fore_tile, back_tile, bord_tile; + static short up_arrow_bits[] = { + 0x0000, 0x0180, 0x03c0, 0x07e0, + 0x0ff0, 0x1ff8, 0x3ffc, 0x7ffe, + 0x0180, 0x0180, 0x0180, 0x0180, + 0x0180, 0x0180, 0x0180, 0xffff}; + static short down_arrow_bits[] = { + 0xffff, 0x0180, 0x0180, 0x0180, + 0x0180, 0x0180, 0x0180, 0x0180, + 0x7ffe, 0x3ffc, 0x1ff8, 0x0ff0, + 0x07e0, 0x03c0, 0x0180, 0x0000}; + + fore_tile = XMakeTile (s->display.x->foreground_pixel); + back_tile = XMakeTile (s->display.x->background_pixel); + bord_tile = XMakeTile (s->display.x->border_pixel); + + b = XStoreBitmap (VSCROLL_WIDTH - 2, VSCROLL_WIDTH - 2, up_arrow_bits); + up_arrow_pixmap = XMakePixmap (b, + s->display.x->foreground_pixel, + s->display.x->background_pixel); + XFreeBitmap (b); + + b = XStoreBitmap (VSCROLL_WIDTH - 2, VSCROLL_WIDTH - 2, down_arrow_bits); + down_arrow_pixmap = XMakePixmap (b, + s->display.x->foreground_pixel, + s->display.x->background_pixel); + XFreeBitmap (b); + + ibw = s->display.x->internal_border_width; + + s->display.x->v_scrollbar = XCreateWindow (s->display.x->window_desc, + width - VSCROLL_WIDTH - ibw/2, + ibw/2, + VSCROLL_WIDTH - 2, + height - ibw - 2, + 1, bord_tile, back_tile); + + s->display.x->v_scrollbar_width = VSCROLL_WIDTH; + + s->display.x->v_thumbup = XCreateWindow (s->display.x->v_scrollbar, + 0, 0, + VSCROLL_WIDTH - 2, + VSCROLL_WIDTH - 2, + 0, 0, up_arrow_pixmap); + XTileAbsolute (s->display.x->v_thumbup); + + s->display.x->v_thumbdown = XCreateWindow (s->display.x->v_scrollbar, + 0, + height - ibw - VSCROLL_WIDTH, + VSCROLL_WIDTH - 2, + VSCROLL_WIDTH - 2, + 0, 0, down_arrow_pixmap); + XTileAbsolute (s->display.x->v_thumbdown); + + s->display.x->v_slider = XCreateWindow (s->display.x->v_scrollbar, + 0, VSCROLL_WIDTH - 2, + VSCROLL_WIDTH - 4, + VSCROLL_WIDTH - 4, + 1, back_tile, fore_tile); + + XSelectInput (s->display.x->v_scrollbar, + (ButtonPressed | ButtonReleased | KeyPressed)); + XSelectInput (s->display.x->v_thumbup, + (ButtonPressed | ButtonReleased | KeyPressed)); + + XSelectInput (s->display.x->v_thumbdown, + (ButtonPressed | ButtonReleased | KeyPressed)); + + XMapWindow (s->display.x->v_thumbup); + XMapWindow (s->display.x->v_thumbdown); + XMapWindow (s->display.x->v_slider); + XMapWindow (s->display.x->v_scrollbar); + + XFreePixmap (fore_tile); + XFreePixmap (back_tile); + XFreePixmap (up_arrow_pixmap); + XFreePixmap (down_arrow_pixmap); +#endif /* not HAVE_X11 */ +} + +static void +install_horizontal_scrollbar (s) + struct screen *s; +{ + int ibw = s->display.x->internal_border_width; + Window parent; + Pixmap left_arrow_pixmap, right_arrow_pixmap, slider_pixmap; + int pix_x, pix_y; + int width; + + pix_x = ibw; + pix_y = PIXEL_HEIGHT (s) - HSCROLL_HEIGHT - ibw ; + width = PIXEL_WIDTH (s) - 2 * ibw; + if (s->display.x->v_scrollbar_width) + width -= (s->display.x->v_scrollbar_width + 1); + +#ifdef HAVE_X11 + left_arrow_pixmap = + XCreatePixmapFromBitmapData (x_current_display, s->display.x->window_desc, + left_arrow_bits, 16, 16, + s->display.x->foreground_pixel, + s->display.x->background_pixel, + DefaultDepth (x_current_display, + XDefaultScreen (x_current_display))); + + right_arrow_pixmap = + XCreatePixmapFromBitmapData (x_current_display, s->display.x->window_desc, + right_arrow_bits, 16, 16, + s->display.x->foreground_pixel, + s->display.x->background_pixel, + DefaultDepth (x_current_display, + XDefaultScreen (x_current_display))); + + slider_pixmap = + XCreatePixmapFromBitmapData (x_current_display, s->display.x->window_desc, + gray_bits, 16, 16, + s->display.x->foreground_pixel, + s->display.x->background_pixel, + DefaultDepth (x_current_display, + XDefaultScreen (x_current_display))); + + left_arrow_cursor = XCreateFontCursor (x_current_display, XC_sb_left_arrow); + right_arrow_cursor = XCreateFontCursor (x_current_display, XC_sb_right_arrow); + h_double_arrow_cursor = XCreateFontCursor (x_current_display, XC_sb_h_double_arrow); + + s->display.x->h_scrollbar = + XCreateSimpleWindow (x_current_display, s->display.x->window_desc, + pix_x, pix_y, + width - ibw - 2, HSCROLL_HEIGHT - 2, 1, + s->display.x->foreground_pixel, + s->display.x->background_pixel); + XDefineCursor (x_current_display, s->display.x->h_scrollbar, + h_double_arrow_cursor); + + s->display.x->h_slider = + XCreateSimpleWindow (x_current_display, s->display.x->h_scrollbar, + 0, 0, + HSCROLL_HEIGHT - 4, HSCROLL_HEIGHT - 4, + 1, s->display.x->foreground_pixel, + s->display.x->background_pixel); + XDefineCursor (x_current_display, s->display.x->h_slider, + h_double_arrow_cursor); + XSetWindowBackgroundPixmap (x_current_display, s->display.x->h_slider, + slider_pixmap); + + s->display.x->h_thumbleft = + XCreateSimpleWindow (x_current_display, s->display.x->h_scrollbar, + 0, 0, + HSCROLL_HEIGHT - 2, HSCROLL_HEIGHT - 2, + 0, s->display.x->foreground_pixel, + s->display.x->background_pixel); + XDefineCursor (x_current_display, s->display.x->h_thumbleft, + left_arrow_cursor); + XSetWindowBackgroundPixmap (x_current_display, s->display.x->h_thumbleft, + left_arrow_pixmap); + + s->display.x->h_thumbright = + XCreateSimpleWindow (x_current_display, s->display.x->h_scrollbar, + width - ibw - HSCROLL_HEIGHT, 0, + HSCROLL_HEIGHT - 2, HSCROLL_HEIGHT -2, + 0, s->display.x->foreground_pixel, + s->display.x->background_pixel); + XDefineCursor (x_current_display, s->display.x->h_thumbright, + right_arrow_cursor); + XSetWindowBackgroundPixmap (x_current_display, s->display.x->h_thumbright, + right_arrow_pixmap); + + XFreePixmap (x_current_display, slider_pixmap); + XFreePixmap (x_current_display, left_arrow_pixmap); + XFreePixmap (x_current_display, right_arrow_pixmap); + + XSelectInput (x_current_display, s->display.x->h_scrollbar, + ButtonPressMask | ButtonReleaseMask + | PointerMotionMask | PointerMotionHintMask + | EnterWindowMask); + XSelectInput (x_current_display, s->display.x->h_slider, + ButtonPressMask | ButtonReleaseMask); + XSelectInput (x_current_display, s->display.x->h_thumbright, + ButtonPressMask | ButtonReleaseMask); + XSelectInput (x_current_display, s->display.x->h_thumbleft, + ButtonPressMask | ButtonReleaseMask); + + XMapWindow (x_current_display, s->display.x->h_scrollbar); + XMapSubwindows (x_current_display, s->display.x->h_scrollbar); +#else /* not HAVE_X11 */ + Bitmap b; + Pixmap fore_tile, back_tile, bord_tile; +#endif +} + +#ifndef HAVE_X11 /* X10 */ +#define XMoveResizeWindow XConfigureWindow +#endif /* not HAVE_X11 */ + +/* Adjust the displayed position in the scroll bar for window W. */ + +void +adjust_scrollbars (s) + struct screen *s; +{ + int pos; + int first_char_in_window, char_beyond_window, chars_in_window; + int chars_in_buffer, buffer_size; + struct window *w = XWINDOW (SCREEN_SELECTED_WINDOW (s)); + + if (s->output_method != output_x_window) + return; + + if (s->display.x->v_scrollbar != 0) + { + int h, height; + struct buffer *b = XBUFFER (w->buffer); + + buffer_size = Z - BEG; + chars_in_buffer = ZV - BEGV; + first_char_in_window = marker_position (w->start); + char_beyond_window = buffer_size + 1 - XFASTINT (w->window_end_pos); + chars_in_window = char_beyond_window - first_char_in_window; + + /* Calculate height of scrollbar area */ + + height = s->height * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width + - 2 * (s->display.x->v_scrollbar_width); + + /* Figure starting position for the scrollbar slider */ + + if (chars_in_buffer <= 0) + pos = 0; + else + pos = ((first_char_in_window - BEGV - BEG) * height + / chars_in_buffer); + pos = max (0, pos); + pos = min (pos, height - 2); + + /* Figure length of the slider */ + + if (chars_in_buffer <= 0) + h = height; + else + h = (chars_in_window * height) / chars_in_buffer; + h = min (h, height - pos); + h = max (h, 1); + + /* Add thumbup offset to starting position of slider */ + + pos += (s->display.x->v_scrollbar_width - 2); + + XMoveResizeWindow (XDISPLAY + s->display.x->v_slider, + 0, pos, + s->display.x->v_scrollbar_width - 4, h); + } + + if (s->display.x->h_scrollbar != 0) + { + int l, length; /* Length of the scrollbar area */ + + length = s->width * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width + - 2 * (s->display.x->h_scrollbar_height); + + /* Starting position for horizontal slider */ + if (! w->hscroll) + pos = 0; + else + pos = (w->hscroll * length) / (w->hscroll + s->width); + pos = max (0, pos); + pos = min (pos, length - 2); + + /* Length of slider */ + l = length - pos; + + /* Add thumbup offset */ + pos += (s->display.x->h_scrollbar_height - 2); + + XMoveResizeWindow (XDISPLAY + s->display.x->h_slider, + pos, 0, + l, s->display.x->h_scrollbar_height - 4); + } +} + +/* Adjust the size of the scroll bars of screen S, + when the screen size has changed. */ + +void +x_resize_scrollbars (s) + struct screen *s; +{ + int ibw = s->display.x->internal_border_width; + int pixelwidth, pixelheight; + + if (s == 0 + || s->display.x == 0 + || (s->display.x->v_scrollbar == 0 + && s->display.x->h_scrollbar == 0)) + return; + + /* Get the size of the screen. */ + pixelwidth = (s->width * FONT_WIDTH (s->display.x->font) + + 2 * ibw + s->display.x->v_scrollbar_width); + pixelheight = (s->height * FONT_HEIGHT (s->display.x->font) + + 2 * ibw + s->display.x->h_scrollbar_height); + + if (s->display.x->v_scrollbar_width && s->display.x->v_scrollbar) + { + BLOCK_INPUT; + XMoveResizeWindow (XDISPLAY + s->display.x->v_scrollbar, + pixelwidth - s->display.x->v_scrollbar_width - ibw/2, + ibw/2, + s->display.x->v_scrollbar_width - 2, + pixelheight - ibw - 2); + XMoveWindow (XDISPLAY + s->display.x->v_thumbdown, 0, + pixelheight - ibw - s->display.x->v_scrollbar_width); + UNBLOCK_INPUT; + } + + if (s->display.x->h_scrollbar_height && s->display.x->h_scrollbar) + { + if (s->display.x->v_scrollbar_width) + pixelwidth -= s->display.x->v_scrollbar_width + 1; + + BLOCK_INPUT; + XMoveResizeWindow (XDISPLAY + s->display.x->h_scrollbar, + ibw / 2, + pixelheight - s->display.x->h_scrollbar_height - ibw / 2, + pixelwidth - ibw - 2, + s->display.x->h_scrollbar_height - 2); + XMoveWindow (XDISPLAY + s->display.x->h_thumbright, + pixelwidth - ibw - s->display.x->h_scrollbar_height, 0); + UNBLOCK_INPUT; + } +} + +x_pixel_width (s) + register struct screen *s; +{ + return PIXEL_WIDTH (s); +} + +x_pixel_height (s) + register struct screen *s; +{ + return PIXEL_HEIGHT (s); +} + +DEFUN ("x-defined-color", Fx_defined_color, Sx_defined_color, 1, 1, 0, + "Return t if the current X display supports the color named COLOR.") + (color) + Lisp_Object color; +{ + Color foo; + + CHECK_STRING (color, 0); + + if (defined_color (XSTRING (color)->data, &foo)) + return Qt; + else + return Qnil; +} + +DEFUN ("x-color-display-p", Fx_color_display_p, Sx_color_display_p, 0, 0, 0, + "Return t if the X display used currently supports color.") + () +{ + if (XINT (x_screen_planes) <= 2) + return Qnil; + + switch (screen_visual->class) + { + case StaticColor: + case PseudoColor: + case TrueColor: + case DirectColor: + return Qt; + + default: + return Qnil; + } +} + +DEFUN ("x-pixel-width", Fx_pixel_width, Sx_pixel_width, 1, 1, 0, + "Return the width in pixels of screen S.") + (screen) + Lisp_Object screen; +{ + CHECK_SCREEN (screen, 0); + return make_number (XSCREEN (screen)->display.x->pixel_width); +} + +DEFUN ("x-pixel-height", Fx_pixel_height, Sx_pixel_height, 1, 1, 0, + "Return the height in pixels of screen S.") + (screen) + Lisp_Object screen; +{ + CHECK_SCREEN (screen, 0); + return make_number (XSCREEN (screen)->display.x->pixel_height); +} + +/* Draw a rectangle on the screen with left top corner including + the character specified by LEFT_CHAR and TOP_CHAR. The rectangle is + CHARS by LINES wide and long and is the color of the cursor. */ + +void +x_rectangle (s, gc, left_char, top_char, chars, lines) + register struct screen *s; + GC gc; + register int top_char, left_char, chars, lines; +{ + int width; + int height; + int left = (left_char * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width); + int top = (top_char * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width); + + if (chars < 0) + width = FONT_WIDTH (s->display.x->font) / 2; + else + width = FONT_WIDTH (s->display.x->font) * chars; + if (lines < 0) + height = FONT_HEIGHT (s->display.x->font) / 2; + else + height = FONT_HEIGHT (s->display.x->font) * lines; + + XDrawRectangle (x_current_display, s->display.x->window_desc, + gc, left, top, width, height); +} + +DEFUN ("x-draw-rectangle", Fx_draw_rectangle, Sx_draw_rectangle, 5, 5, 0, + "Draw a rectangle on SCREEN between coordinates specified by\n\ +numbers X0, Y0, X1, Y1 in the cursor pixel.") + (screen, X0, Y0, X1, Y1) + register Lisp_Object screen, X0, X1, Y0, Y1; +{ + register int x0, y0, x1, y1, top, left, n_chars, n_lines; + + CHECK_SCREEN (screen, 0); + CHECK_NUMBER (X0, 0); + CHECK_NUMBER (Y0, 1); + CHECK_NUMBER (X1, 2); + CHECK_NUMBER (Y1, 3); + + x0 = XINT (X0); + x1 = XINT (X1); + y0 = XINT (Y0); + y1 = XINT (Y1); + + if (y1 > y0) + { + top = y0; + n_lines = y1 - y0 + 1; + } + else + { + top = y1; + n_lines = y0 - y1 + 1; + } + + if (x1 > x0) + { + left = x0; + n_chars = x1 - x0 + 1; + } + else + { + left = x1; + n_chars = x0 - x1 + 1; + } + + BLOCK_INPUT; + x_rectangle (XSCREEN (screen), XSCREEN (screen)->display.x->cursor_gc, + left, top, n_chars, n_lines); + UNBLOCK_INPUT; + + return Qt; +} + +DEFUN ("x-erase-rectangle", Fx_erase_rectangle, Sx_erase_rectangle, 5, 5, 0, + "Draw a rectangle drawn on SCREEN between coordinates\n\ +X0, Y0, X1, Y1 in the regular background-pixel.") + (screen, X0, Y0, X1, Y1) + register Lisp_Object screen, X0, Y0, X1, Y1; +{ + register int x0, y0, x1, y1, top, left, n_chars, n_lines; + + CHECK_SCREEN (screen, 0); + CHECK_NUMBER (X0, 0); + CHECK_NUMBER (Y0, 1); + CHECK_NUMBER (X1, 2); + CHECK_NUMBER (Y1, 3); + + x0 = XINT (X0); + x1 = XINT (X1); + y0 = XINT (Y0); + y1 = XINT (Y1); + + if (y1 > y0) + { + top = y0; + n_lines = y1 - y0 + 1; + } + else + { + top = y1; + n_lines = y0 - y1 + 1; + } + + if (x1 > x0) + { + left = x0; + n_chars = x1 - x0 + 1; + } + else + { + left = x1; + n_chars = x0 - x1 + 1; + } + + BLOCK_INPUT; + x_rectangle (XSCREEN (screen), XSCREEN (screen)->display.x->reverse_gc, + left, top, n_chars, n_lines); + UNBLOCK_INPUT; + + return Qt; +} + +/* Draw lines around the text region beginning at the character position + TOP_X, TOP_Y and ending at BOTTOM_X and BOTTOM_Y. GC specifies the + pixel and line characteristics. */ + +#define line_len(line) (SCREEN_CURRENT_GLYPHS (s)->used[(line)]) + +static void +outline_region (s, gc, top_x, top_y, bottom_x, bottom_y) + register struct screen *s; + GC gc; + int top_x, top_y, bottom_x, bottom_y; +{ + register int ibw = s->display.x->internal_border_width; + register int font_w = FONT_WIDTH (s->display.x->font); + register int font_h = FONT_HEIGHT (s->display.x->font); + int y = top_y; + int x = line_len (y); + XPoint *pixel_points = (XPoint *) + alloca (((bottom_y - top_y + 2) * 4) * sizeof (XPoint)); + register XPoint *this_point = pixel_points; + + /* Do the horizontal top line/lines */ + if (top_x == 0) + { + this_point->x = ibw; + this_point->y = ibw + (font_h * top_y); + this_point++; + if (x == 0) + this_point->x = ibw + (font_w / 2); /* Half-size for newline chars. */ + else + this_point->x = ibw + (font_w * x); + this_point->y = (this_point - 1)->y; + } + else + { + this_point->x = ibw; + this_point->y = ibw + (font_h * (top_y + 1)); + this_point++; + this_point->x = ibw + (font_w * top_x); + this_point->y = (this_point - 1)->y; + this_point++; + this_point->x = (this_point - 1)->x; + this_point->y = ibw + (font_h * top_y); + this_point++; + this_point->x = ibw + (font_w * x); + this_point->y = (this_point - 1)->y; + } + + /* Now do the right side. */ + while (y < bottom_y) + { /* Right vertical edge */ + this_point++; + this_point->x = (this_point - 1)->x; + this_point->y = ibw + (font_h * (y + 1)); + this_point++; + + y++; /* Horizontal connection to next line */ + x = line_len (y); + if (x == 0) + this_point->x = ibw + (font_w / 2); + else + this_point->x = ibw + (font_w * x); + + this_point->y = (this_point - 1)->y; + } + + /* Now do the bottom and connect to the top left point. */ + this_point->x = ibw + (font_w * (bottom_x + 1)); + + this_point++; + this_point->x = (this_point - 1)->x; + this_point->y = ibw + (font_h * (bottom_y + 1)); + this_point++; + this_point->x = ibw; + this_point->y = (this_point - 1)->y; + this_point++; + this_point->x = pixel_points->x; + this_point->y = pixel_points->y; + + XDrawLines (x_current_display, s->display.x->window_desc, + gc, pixel_points, + (this_point - pixel_points + 1), CoordModeOrigin); +} + +DEFUN ("x-contour-region", Fx_contour_region, Sx_contour_region, 1, 1, 0, + "Highlight the region between point and the character under the mouse\n\ +selected screen.") + (event) + register Lisp_Object event; +{ + register int x0, y0, x1, y1; + register struct screen *s = selected_screen; + register int p1, p2; + + CHECK_CONS (event, 0); + + BLOCK_INPUT; + x0 = XINT (Fcar (Fcar (event))); + y0 = XINT (Fcar (Fcdr (Fcar (event)))); + + /* If the mouse is past the end of the line, don't that area. */ + /* ReWrite this... */ + + x1 = s->cursor_x; + y1 = s->cursor_y; + + if (y1 > y0) /* point below mouse */ + outline_region (s, s->display.x->cursor_gc, + x0, y0, x1, y1); + else if (y1 < y0) /* point above mouse */ + outline_region (s, s->display.x->cursor_gc, + x1, y1, x0, y0); + else /* same line: draw horizontal rectangle */ + { + if (x1 > x0) + x_rectangle (s, s->display.x->cursor_gc, + x0, y0, (x1 - x0 + 1), 1); + else if (x1 < x0) + x_rectangle (s, s->display.x->cursor_gc, + x1, y1, (x0 - x1 + 1), 1); + } + + XFlush (x_current_display); + UNBLOCK_INPUT; + + return Qnil; +} + +DEFUN ("x-uncontour-region", Fx_uncontour_region, Sx_uncontour_region, 1, 1, 0, + "Erase any highlighting of the region between point and the character\n\ +at X, Y on the selected screen.") + (event) + register Lisp_Object event; +{ + register int x0, y0, x1, y1; + register struct screen *s = selected_screen; + + BLOCK_INPUT; + x0 = XINT (Fcar (Fcar (event))); + y0 = XINT (Fcar (Fcdr (Fcar (event)))); + x1 = s->cursor_x; + y1 = s->cursor_y; + + if (y1 > y0) /* point below mouse */ + outline_region (s, s->display.x->reverse_gc, + x0, y0, x1, y1); + else if (y1 < y0) /* point above mouse */ + outline_region (s, s->display.x->reverse_gc, + x1, y1, x0, y0); + else /* same line: draw horizontal rectangle */ + { + if (x1 > x0) + x_rectangle (s, s->display.x->reverse_gc, + x0, y0, (x1 - x0 + 1), 1); + else if (x1 < x0) + x_rectangle (s, s->display.x->reverse_gc, + x1, y1, (x0 - x1 + 1), 1); + } + UNBLOCK_INPUT; + + return Qnil; +} + +extern unsigned int x_mouse_x, x_mouse_y, x_mouse_grabbed; +extern Lisp_Object unread_command_char; + +#if 0 +int contour_begin_x, contour_begin_y; +int contour_end_x, contour_end_y; +int contour_npoints; + +/* Clip the top part of the contour lines down (and including) line Y_POS. + If X_POS is in the middle (rather than at the end) of the line, drop + down a line at that character. */ + +static void +clip_contour_top (y_pos, x_pos) +{ + register XPoint *begin = contour_lines[y_pos].top_left; + register XPoint *end; + register int npoints; + register struct display_line *line = selected_screen->phys_lines[y_pos + 1]; + + if (x_pos >= line->len - 1) /* Draw one, straight horizontal line. */ + { + end = contour_lines[y_pos].top_right; + npoints = (end - begin + 1); + XDrawLines (x_current_display, contour_window, + contour_erase_gc, begin_erase, npoints, CoordModeOrigin); + + bcopy (end, begin + 1, contour_last_point - end + 1); + contour_last_point -= (npoints - 2); + XDrawLines (x_current_display, contour_window, + contour_erase_gc, begin, 2, CoordModeOrigin); + XFlush (x_current_display); + + /* Now, update contour_lines structure. */ + } + /* ______. */ + else /* |________*/ + { + register XPoint *p = begin + 1; + end = contour_lines[y_pos].bottom_right; + npoints = (end - begin + 1); + XDrawLines (x_current_display, contour_window, + contour_erase_gc, begin_erase, npoints, CoordModeOrigin); + + p->y = begin->y; + p->x = ibw + (font_w * (x_pos + 1)); + p++; + p->y = begin->y + font_h; + p->x = (p - 1)->x; + bcopy (end, begin + 3, contour_last_point - end + 1); + contour_last_point -= (npoints - 5); + XDrawLines (x_current_display, contour_window, + contour_erase_gc, begin, 4, CoordModeOrigin); + XFlush (x_current_display); + + /* Now, update contour_lines structure. */ + } +} + +/* Erase the top horzontal lines of the contour, and then extend + the contour upwards. */ + +static void +extend_contour_top (line) +{ +} + +static void +clip_contour_bottom (x_pos, y_pos) + int x_pos, y_pos; +{ +} + +static void +extend_contour_bottom (x_pos, y_pos) +{ +} + +DEFUN ("x-select-region", Fx_select_region, Sx_select_region, 1, 1, "e", + "") + (event) + Lisp_Object event; +{ + register struct screen *s = selected_screen; + register int point_x = s->cursor_x; + register int point_y = s->cursor_y; + register int mouse_below_point; + register Lisp_Object obj; + register int x_contour_x, x_contour_y; + + x_contour_x = x_mouse_x; + x_contour_y = x_mouse_y; + if (x_contour_y > point_y || (x_contour_y == point_y + && x_contour_x > point_x)) + { + mouse_below_point = 1; + outline_region (s, s->display.x->cursor_gc, point_x, point_y, + x_contour_x, x_contour_y); + } + else + { + mouse_below_point = 0; + outline_region (s, s->display.x->cursor_gc, x_contour_x, x_contour_y, + point_x, point_y); + } + + while (1) + { + obj = read_char (-1); + if (XTYPE (obj) != Lisp_Cons) + break; + + if (mouse_below_point) + { + if (x_mouse_y <= point_y) /* Flipped. */ + { + mouse_below_point = 0; + + outline_region (s, s->display.x->reverse_gc, point_x, point_y, + x_contour_x, x_contour_y); + outline_region (s, s->display.x->cursor_gc, x_mouse_x, x_mouse_y, + point_x, point_y); + } + else if (x_mouse_y < x_contour_y) /* Bottom clipped. */ + { + clip_contour_bottom (x_mouse_y); + } + else if (x_mouse_y > x_contour_y) /* Bottom extended. */ + { + extend_bottom_contour (x_mouse_y); + } + + x_contour_x = x_mouse_x; + x_contour_y = x_mouse_y; + } + else /* mouse above or same line as point */ + { + if (x_mouse_y >= point_y) /* Flipped. */ + { + mouse_below_point = 1; + + outline_region (s, s->display.x->reverse_gc, + x_contour_x, x_contour_y, point_x, point_y); + outline_region (s, s->display.x->cursor_gc, point_x, point_y, + x_mouse_x, x_mouse_y); + } + else if (x_mouse_y > x_contour_y) /* Top clipped. */ + { + clip_contour_top (x_mouse_y); + } + else if (x_mouse_y < x_contour_y) /* Top extended. */ + { + extend_contour_top (x_mouse_y); + } + } + } + + unread_command_char = obj; + if (mouse_below_point) + { + contour_begin_x = point_x; + contour_begin_y = point_y; + contour_end_x = x_contour_x; + contour_end_y = x_contour_y; + } + else + { + contour_begin_x = x_contour_x; + contour_begin_y = x_contour_y; + contour_end_x = point_x; + contour_end_y = point_y; + } +} +#endif + +DEFUN ("x-horizontal-line", Fx_horizontal_line, Sx_horizontal_line, 1, 1, "e", + "") + (event) + Lisp_Object event; +{ + register Lisp_Object obj; + struct screen *s = selected_screen; + register struct window *w = XWINDOW (selected_window); + register GC line_gc = s->display.x->cursor_gc; + register GC erase_gc = s->display.x->reverse_gc; +#if 0 + char dash_list[] = {6, 4, 6, 4}; + int dashes = 4; + XGCValues gc_values; +#endif + register int previous_y; + register int line = (x_mouse_y + 1) * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width; + register int left = s->display.x->internal_border_width + + (w->left + * FONT_WIDTH (s->display.x->font)); + register int right = left + (w->width + * FONT_WIDTH (s->display.x->font)) + - s->display.x->internal_border_width; + +#if 0 + BLOCK_INPUT; + gc_values.foreground = s->display.x->cursor_pixel; + gc_values.background = s->display.x->background_pixel; + gc_values.line_width = 1; + gc_values.line_style = LineOnOffDash; + gc_values.cap_style = CapRound; + gc_values.join_style = JoinRound; + + line_gc = XCreateGC (x_current_display, s->display.x->window_desc, + GCLineStyle | GCJoinStyle | GCCapStyle + | GCLineWidth | GCForeground | GCBackground, + &gc_values); + XSetDashes (x_current_display, line_gc, 0, dash_list, dashes); + gc_values.foreground = s->display.x->background_pixel; + gc_values.background = s->display.x->foreground_pixel; + erase_gc = XCreateGC (x_current_display, s->display.x->window_desc, + GCLineStyle | GCJoinStyle | GCCapStyle + | GCLineWidth | GCForeground | GCBackground, + &gc_values); + XSetDashes (x_current_display, erase_gc, 0, dash_list, dashes); +#endif + + while (1) + { + BLOCK_INPUT; + if (x_mouse_y >= XINT (w->top) + && x_mouse_y < XINT (w->top) + XINT (w->height) - 1) + { + previous_y = x_mouse_y; + line = (x_mouse_y + 1) * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width; + XDrawLine (x_current_display, s->display.x->window_desc, + line_gc, left, line, right, line); + } + XFlushQueue (); + UNBLOCK_INPUT; + + do + { + obj = read_char (-1); + if ((XTYPE (obj) != Lisp_Cons) + || (! EQ (Fcar (Fcdr (Fcdr (obj))), + intern ("vertical-scroll-bar"))) + || x_mouse_grabbed) + { + BLOCK_INPUT; + XDrawLine (x_current_display, s->display.x->window_desc, + erase_gc, left, line, right, line); + UNBLOCK_INPUT; + unread_command_char = obj; +#if 0 + XFreeGC (x_current_display, line_gc); + XFreeGC (x_current_display, erase_gc); +#endif + return Qnil; + } + } + while (x_mouse_y == previous_y); + + BLOCK_INPUT; + XDrawLine (x_current_display, s->display.x->window_desc, + erase_gc, left, line, right, line); + UNBLOCK_INPUT; + } +} + +static Cursor grabbed_cursor; + +DEFUN ("x-grab-pointer", Fx_grab_pointer, Sx_grab_pointer, 0, 2, 0, + "Grab the pointer and restrict it to its current window. If optional\n\ +SHAPE is non-nil, change the pointer shape to that. If second optional\n\ +argument MOUSE-ONLY is non-nil, ignore keyboard events during the grab.") + (shape, ignore_keyboard) + Lisp_Object shape, ignore_keyboard; +{ + Window w; + int pointer_mode, result; + + BLOCK_INPUT; + if (! NULL (ignore_keyboard)) + pointer_mode = GrabModeSync; + else + pointer_mode = GrabModeAsync; + + if (! NULL (shape)) + { + CHECK_NUMBER (shape, 0); + grabbed_cursor = XCreateFontCursor (x_current_display, XINT (shape)); + } + + /* Determine which window to confine the mouse to. */ + if (EQ (Vmouse_screen_part, Qtext_part) || EQ (Vmouse_screen_part, Qmodeline_part)) + { + w = x_focus_screen->display.x->window_desc; + } + else if (EQ (Vmouse_screen_part, Qvscrollbar_part) + || EQ (Vmouse_screen_part, Qvslider_part)) + { + w = x_focus_screen->display.x->v_scrollbar; + } + else if (EQ (Vmouse_screen_part, Qvthumbup_part)) + { + w = x_focus_screen->display.x->v_thumbup; + } + else if (EQ (Vmouse_screen_part, Qvthumbdown_part)) + { + w = x_focus_screen->display.x->v_thumbdown; + } + else if (EQ (Vmouse_screen_part, Qhscrollbar_part) + || EQ (Vmouse_screen_part, Qhslider_part)) + { + w = x_focus_screen->display.x->h_scrollbar; + } + else if (EQ (Vmouse_screen_part, Qhthumbleft_part)) + { + w = x_focus_screen->display.x->h_thumbleft; + } + else if (EQ (Vmouse_screen_part, Qhthumbright_part)) + { + w = x_focus_screen->display.x->h_thumbright; + } + else + abort (); + + result = XGrabPointer (x_current_display, w, + False, + ButtonMotionMask | ButtonPressMask + | ButtonReleaseMask | PointerMotionHintMask, + GrabModeAsync, /* Keep pointer events flowing */ + pointer_mode, /* Stall keyboard events */ + w, /* Stay in this window */ + grabbed_cursor, + CurrentTime); + if (result == GrabSuccess) + { + UNBLOCK_INPUT; + return Qt; + } + + XFreeCursor (x_current_display, grabbed_cursor); + UNBLOCK_INPUT; + return Qnil; +} + +DEFUN ("x-ungrab-pointer", Fx_ungrab_pointer, Sx_ungrab_pointer, 0, 0, 0, + "Release the pointer.") + () +{ + BLOCK_INPUT; + XUngrabPointer (x_current_display, CurrentTime); + + if (! ((int) grabbed_cursor)) + { + XFreeCursor (x_current_display, grabbed_cursor); + grabbed_cursor = (Cursor) 0; + } + + UNBLOCK_INPUT; + return Qnil; +} + +/* Offset in buffer of character under the pointer, or 0. */ +int mouse_buffer_offset; + +#if 0 +/* These keep track of the rectangle following the pointer. */ +int mouse_track_top, mouse_track_left, mouse_track_width; + +DEFUN ("x-track-pointer", Fx_track_pointer, Sx_track_pointer, 0, 0, 0, + "Track the pointer.") + () +{ + static Cursor current_pointer_shape; + SCREEN_PTR s = x_mouse_screen; + + BLOCK_INPUT; + if (EQ (Vmouse_screen_part, Qtext_part) + && (current_pointer_shape != s->display.x->nontext_cursor)) + { + unsigned char c; + struct buffer *buf; + + current_pointer_shape = s->display.x->nontext_cursor; + XDefineCursor (x_current_display, + s->display.x->window_desc, + current_pointer_shape); + + buf = XBUFFER (XWINDOW (Vmouse_window)->buffer); + c = *(BUF_CHAR_ADDRESS (buf, mouse_buffer_offset)); + } + else if (EQ (Vmouse_screen_part, Qmodeline_part) + && (current_pointer_shape != s->display.x->modeline_cursor)) + { + current_pointer_shape = s->display.x->modeline_cursor; + XDefineCursor (x_current_display, + s->display.x->window_desc, + current_pointer_shape); + } + + XFlushQueue (); + UNBLOCK_INPUT; +} +#endif + +#if 0 +DEFUN ("x-track-pointer", Fx_track_pointer, Sx_track_pointer, 1, 1, "e", + "Draw rectangle around character under mouse pointer, if there is one.") + (event) + Lisp_Object event; +{ + struct window *w = XWINDOW (Vmouse_window); + struct screen *s = XSCREEN (WINDOW_SCREEN (w)); + struct buffer *b = XBUFFER (w->buffer); + Lisp_Object obj; + + if (! EQ (Vmouse_window, selected_window)) + return Qnil; + + if (EQ (event, Qnil)) + { + int x, y; + + x_read_mouse_position (selected_screen, &x, &y); + } + + BLOCK_INPUT; + mouse_track_width = 0; + mouse_track_left = mouse_track_top = -1; + + do + { + if ((x_mouse_x != mouse_track_left + && (x_mouse_x < mouse_track_left + || x_mouse_x > (mouse_track_left + mouse_track_width))) + || x_mouse_y != mouse_track_top) + { + int hp = 0; /* Horizontal position */ + int len = SCREEN_CURRENT_GLYPHS (s)->used[x_mouse_y]; + int p = SCREEN_CURRENT_GLYPHS (s)->bufp[x_mouse_y]; + int tab_width = XINT (b->tab_width); + int ctl_arrow_p = !NULL (b->ctl_arrow); + unsigned char c; + int mode_line_vpos = XFASTINT (w->height) + XFASTINT (w->top) - 1; + int in_mode_line = 0; + + if (! SCREEN_CURRENT_GLYPHS (s)->enable[x_mouse_y]) + break; + + /* Erase previous rectangle. */ + if (mouse_track_width) + { + x_rectangle (s, s->display.x->reverse_gc, + mouse_track_left, mouse_track_top, + mouse_track_width, 1); + + if ((mouse_track_left == s->phys_cursor_x + || mouse_track_left == s->phys_cursor_x - 1) + && mouse_track_top == s->phys_cursor_y) + { + x_display_cursor (s, 1); + } + } + + mouse_track_left = x_mouse_x; + mouse_track_top = x_mouse_y; + mouse_track_width = 0; + + if (mouse_track_left > len) /* Past the end of line. */ + goto draw_or_not; + + if (mouse_track_top == mode_line_vpos) + { + in_mode_line = 1; + goto draw_or_not; + } + + if (tab_width <= 0 || tab_width > 20) tab_width = 8; + do + { + c = FETCH_CHAR (p); + if (len == s->width && hp == len - 1 && c != '\n') + goto draw_or_not; + + switch (c) + { + case '\t': + mouse_track_width = tab_width - (hp % tab_width); + p++; + hp += mouse_track_width; + if (hp > x_mouse_x) + { + mouse_track_left = hp - mouse_track_width; + goto draw_or_not; + } + continue; + + case '\n': + mouse_track_width = -1; + goto draw_or_not; + + default: + if (ctl_arrow_p && (c < 040 || c == 0177)) + { + if (p > ZV) + goto draw_or_not; + + mouse_track_width = 2; + p++; + hp +=2; + if (hp > x_mouse_x) + { + mouse_track_left = hp - mouse_track_width; + goto draw_or_not; + } + } + else + { + mouse_track_width = 1; + p++; + hp++; + } + continue; + } + } + while (hp <= x_mouse_x); + + draw_or_not: + if (mouse_track_width) /* Over text; use text pointer shape. */ + { + XDefineCursor (x_current_display, + s->display.x->window_desc, + s->display.x->text_cursor); + x_rectangle (s, s->display.x->cursor_gc, + mouse_track_left, mouse_track_top, + mouse_track_width, 1); + } + else if (in_mode_line) + XDefineCursor (x_current_display, + s->display.x->window_desc, + s->display.x->modeline_cursor); + else + XDefineCursor (x_current_display, + s->display.x->window_desc, + s->display.x->nontext_cursor); + } + + XFlush (x_current_display); + UNBLOCK_INPUT; + + obj = read_char (-1); + BLOCK_INPUT; + } + while (XTYPE (obj) == Lisp_Cons /* Mouse event */ + && EQ (Fcar (Fcdr (Fcdr (obj))), Qnil) /* Not scrollbar */ + && EQ (Vmouse_depressed, Qnil) /* Only motion events */ + && EQ (Vmouse_window, selected_window) /* In this window */ + && x_mouse_screen); + + unread_command_char = obj; + + if (mouse_track_width) + { + x_rectangle (s, s->display.x->reverse_gc, + mouse_track_left, mouse_track_top, + mouse_track_width, 1); + mouse_track_width = 0; + if ((mouse_track_left == s->phys_cursor_x + || mouse_track_left - 1 == s->phys_cursor_x) + && mouse_track_top == s->phys_cursor_y) + { + x_display_cursor (s, 1); + } + } + XDefineCursor (x_current_display, + s->display.x->window_desc, + s->display.x->nontext_cursor); + XFlush (x_current_display); + UNBLOCK_INPUT; + + return Qnil; +} +#endif + +#if 0 +#include "glyphs.h" + +/* Draw a pixmap specified by IMAGE_DATA of dimensions WIDTH and HEIGHT + on the screen S at position X, Y. */ + +x_draw_pixmap (s, x, y, image_data, width, height) + struct screen *s; + int x, y, width, height; + char *image_data; +{ + Pixmap image; + + image = XCreateBitmapFromData (x_current_display, + s->display.x->window_desc, image_data, + width, height); + XCopyPlane (x_current_display, image, s->display.x->window_desc, + s->display.x->normal_gc, 0, 0, width, height, x, y); +} +#endif + +x_read_mouse_position (s, x, y) + struct screen *s; + int *x, *y; +{ + Window w; + int ix, iy; + int ibw = s->display.x->internal_border_width; + +#ifdef HAVE_X11 + Window root_window; + int root_x, root_y; + unsigned int keys_and_buttons; + + BLOCK_INPUT; + if (XQueryPointer (x_current_display, s->display.x->window_desc, + &root_window, &w, &root_x, &root_y, &ix, &iy, + &keys_and_buttons) == False) + { + UNBLOCK_INPUT; + error ("Pointer not on same screen as window."); + } + UNBLOCK_INPUT; +#else + BLOCK_INPUT; + XQueryMouse (s->display.x->window_desc, &ix, &iy, &w); + UNBLOCK_INPUT; +#endif /* not HAVE_X11 */ + + x_mouse_x = *x = (ix - ibw) / FONT_WIDTH (s->display.x->font); + x_mouse_y = *y = (iy - ibw) / FONT_HEIGHT (s->display.x->font); +} + +#if 0 + +#ifdef HAVE_X11 +#define XMouseEvent XEvent +#define WhichMouseButton xbutton.button +#define MouseWindow xbutton.window +#define MouseX xbutton.x +#define MouseY xbutton.y +#define MouseTime xbutton.time +#define ButtonReleased ButtonRelease +#define ButtonPressed ButtonPress +#else +#define XMouseEvent XButtonEvent +#define WhichMouseButton detail +#define MouseWindow window +#define MouseX x +#define MouseY y +#define MouseTime time +#endif /* X11 */ + +DEFUN ("x-mouse-events", Fx_mouse_events, Sx_mouse_events, 0, 0, 0, + "Return number of pending mouse events from X window system.") + () +{ + return make_number (queue_event_count (&x_mouse_queue)); +} + +/* Encode the mouse button events in the form expected by the + mouse code in Lisp. For X11, this means moving the masks around. */ + +static int +encode_mouse_button (mouse_event) + XMouseEvent mouse_event; +{ + register int event_code; + register char key_mask; + + event_code = mouse_event.detail & 3; + key_mask = (mouse_event.detail >> 8) & 0xf0; + event_code |= key_mask >> 1; + if (mouse_event.type == ButtonReleased) event_code |= 0x04; + return event_code; +} + +DEFUN ("x-get-mouse-event", Fx_get_mouse_event, Sx_get_mouse_event, + 0, 1, 0, + "Get next mouse event out of mouse event buffer.\n\ +Optional ARG non-nil means return nil immediately if no pending event;\n\ +otherwise, wait for an event. Returns a four-part list:\n\ + ((X-POS Y-POS) WINDOW SCREEN-PART KEYSEQ TIMESTAMP).\n\ +Normally X-POS and Y-POS are the position of the click on the screen\n\ + (measured in characters and lines), and WINDOW is the window clicked in.\n\ +KEYSEQ is a string, the key sequence to be looked up in the mouse maps.\n\ +If SCREEN-PART is non-nil, the event was on a scrollbar;\n\ +then Y-POS is really the total length of the scrollbar, while X-POS is\n\ +the relative position of the scrollbar's value within that total length,\n\ +and a third element OFFSET appears in that list: the height of the thumb-up\n\ +area at the top of the scroll bar.\n\ +SCREEN-PART is one of the following symbols:\n\ + `vertical-scrollbar', `vertical-thumbup', `vertical-thumbdown',\n\ + `horizontal-scrollbar', `horizontal-thumbleft', `horizontal-thumbright'.\n\ +TIMESTAMP is the lower 23 bits of the X-server's timestamp for\n\ +the mouse event.") + (arg) + Lisp_Object arg; +{ + XMouseEvent xrep; + register int com_letter; + register Lisp_Object tempx; + register Lisp_Object tempy; + Lisp_Object part, pos, timestamp; + int prefix; + struct screen *s; + + int tem; + + while (1) + { + BLOCK_INPUT; + tem = dequeue_event (&xrep, &x_mouse_queue); + UNBLOCK_INPUT; + + if (tem) + { + switch (xrep.type) + { + case ButtonPressed: + case ButtonReleased: + + com_letter = encode_mouse_button (xrep); + mouse_timestamp = xrep.MouseTime; + + if ((s = x_window_to_screen (xrep.MouseWindow)) != 0) + { + Lisp_Object screen; + + if (s->display.x->icon_desc == xrep.MouseWindow) + { + x_make_screen_visible (s); + continue; + } + + XSET (tempx, Lisp_Int, + min (s->width-1, max (0, (xrep.MouseX - s->display.x->internal_border_width)/FONT_WIDTH (s->display.x->font)))); + XSET (tempy, Lisp_Int, + min (s->height-1, max (0, (xrep.MouseY - s->display.x->internal_border_width)/FONT_HEIGHT (s->display.x->font)))); + XSET (timestamp, Lisp_Int, (xrep.MouseTime & 0x7fffff)); + XSET (screen, Lisp_Screen, s); + + pos = Fcons (tempx, Fcons (tempy, Qnil)); + Vmouse_window + = Flocate_window_from_coordinates (screen, pos); + + Vmouse_event + = Fcons (pos, + Fcons (Vmouse_window, + Fcons (Qnil, + Fcons (Fchar_to_string (make_number (com_letter)), + Fcons (timestamp, Qnil))))); + return Vmouse_event; + } + else if ((s = x_window_to_scrollbar (xrep.MouseWindow, &part, &prefix)) != 0) + { + int pos, len; + Lisp_Object keyseq; + char *partname; + + keyseq = concat2 (Fchar_to_string (make_number (prefix)), + Fchar_to_string (make_number (com_letter))); + + pos = xrep.MouseY - (s->display.x->v_scrollbar_width - 2); + XSET (tempx, 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 (tempy, Lisp_Int, len); + XSET (timestamp, Lisp_Int, (xrep.MouseTime & 0x7fffff)); + Vmouse_window = s->selected_window; + Vmouse_event + = Fcons (Fcons (tempx, Fcons (tempy, + Fcons (make_number (s->display.x->v_scrollbar_width - 2), + Qnil))), + Fcons (Vmouse_window, + Fcons (intern (part), + Fcons (keyseq, Fcons (timestamp, + Qnil))))); + return Vmouse_event; + } + else + continue; + +#ifdef HAVE_X11 + case MotionNotify: + + com_letter = x11_encode_mouse_button (xrep); + if ((s = x_window_to_screen (xrep.MouseWindow)) != 0) + { + Lisp_Object screen; + + XSET (tempx, Lisp_Int, + min (s->width-1, + max (0, (xrep.MouseX - s->display.x->internal_border_width) + / FONT_WIDTH (s->display.x->font)))); + XSET (tempy, Lisp_Int, + min (s->height-1, + max (0, (xrep.MouseY - s->display.x->internal_border_width) + / FONT_HEIGHT (s->display.x->font)))); + + XSET (screen, Lisp_Screen, s); + XSET (timestamp, Lisp_Int, (xrep.MouseTime & 0x7fffff)); + + pos = Fcons (tempx, Fcons (tempy, Qnil)); + Vmouse_window + = Flocate_window_from_coordinates (screen, pos); + + Vmouse_event + = Fcons (pos, + Fcons (Vmouse_window, + Fcons (Qnil, + Fcons (Fchar_to_string (make_number (com_letter)), + Fcons (timestamp, Qnil))))); + return Vmouse_event; + } + + break; +#endif /* HAVE_X11 */ + + default: + if (s = x_window_to_screen (xrep.MouseWindow)) + Vmouse_window = s->selected_window; + else if (s = x_window_to_scrollbar (xrep.MouseWindow, &part, &prefix)) + Vmouse_window = s->selected_window; + return Vmouse_event = Qnil; + } + } + + if (!NULL (arg)) + return Qnil; + + /* Wait till we get another mouse event. */ + wait_reading_process_input (0, 0, 2, 0); + } +} +#endif + + +#ifndef HAVE_X11 +DEFUN ("x-store-cut-buffer", Fx_store_cut_buffer, Sx_store_cut_buffer, + 1, 1, "sStore text in cut buffer: ", + "Store contents of STRING into the cut buffer of the X window system.") + (string) + register Lisp_Object string; +{ + int mask; + + CHECK_STRING (string, 1); + if (selected_screen->output_method != output_x_window) + error ("Selected screen does not understand X protocol."); + + BLOCK_INPUT; + XStoreBytes ((char *) XSTRING (string)->data, XSTRING (string)->size); + UNBLOCK_INPUT; + + return Qnil; +} + +DEFUN ("x-get-cut-buffer", Fx_get_cut_buffer, Sx_get_cut_buffer, 0, 0, 0, + "Return contents of cut buffer of the X window system, as a string.") + () +{ + int len; + register Lisp_Object string; + int mask; + register char *d; + + BLOCK_INPUT; + d = XFetchBytes (&len); + string = make_string (d, len); + XFree (d); + UNBLOCK_INPUT; + return string; +} +#endif /* X10 */ + +#ifdef HAVE_X11 +DEFUN ("x-rebind-key", Fx_rebind_key, Sx_rebind_key, 3, 3, 0, +"Rebind X keysym KEYSYM, with MODIFIERS, to generate NEWSTRING.\n\ +KEYSYM is a string which conforms to the X keysym definitions found\n\ +in X11/keysymdef.h, sans the initial XK_. MODIFIERS is nil or a\n\ +list of strings specifying modifier keys such as Control_L, which must\n\ +also be depressed for NEWSTRING to appear.") + (x_keysym, modifiers, newstring) + register Lisp_Object x_keysym; + register Lisp_Object modifiers; + register Lisp_Object newstring; +{ + char *rawstring; + register KeySym keysym, modifier_list[16]; + + CHECK_STRING (x_keysym, 1); + CHECK_STRING (newstring, 3); + + keysym = XStringToKeysym ((char *) XSTRING (x_keysym)->data); + if (keysym == NoSymbol) + error ("Keysym does not exist"); + + if (NULL (modifiers)) + XRebindKeysym (x_current_display, keysym, modifier_list, 0, + XSTRING (newstring)->data, XSTRING (newstring)->size); + else + { + register Lisp_Object rest, mod; + register int i = 0; + + for (rest = modifiers; !NULL (rest); rest = Fcdr (rest)) + { + if (i == 16) + error ("Can't have more than 16 modifiers"); + + mod = Fcar (rest); + CHECK_STRING (mod, 3); + modifier_list[i] = XStringToKeysym ((char *) XSTRING (mod)->data); + if (modifier_list[i] == NoSymbol + || !IsModifierKey (modifier_list[i])) + error ("Element is not a modifier keysym"); + i++; + } + + XRebindKeysym (x_current_display, keysym, modifier_list, i, + XSTRING (newstring)->data, XSTRING (newstring)->size); + } + + return Qnil; +} + +DEFUN ("x-rebind-keys", Fx_rebind_keys, Sx_rebind_keys, 2, 2, 0, + "Rebind KEYCODE to list of strings STRINGS.\n\ +STRINGS should be a list of 16 elements, one for each shift combination.\n\ +nil as element means don't change.\n\ +See the documentation of `x-rebind-key' for more information.") + (keycode, strings) + register Lisp_Object keycode; + register Lisp_Object strings; +{ + register Lisp_Object item; + register unsigned char *rawstring; + KeySym rawkey, modifier[1]; + int strsize; + register unsigned i; + + CHECK_NUMBER (keycode, 1); + CHECK_CONS (strings, 2); + rawkey = (KeySym) ((unsigned) (XINT (keycode))) & 255; + for (i = 0; i <= 15; strings = Fcdr (strings), i++) + { + item = Fcar (strings); + if (!NULL (item)) + { + CHECK_STRING (item, 2); + strsize = XSTRING (item)->size; + rawstring = (unsigned char *) xmalloc (strsize); + bcopy (XSTRING (item)->data, rawstring, strsize); + modifier[1] = 1 << i; + XRebindKeysym (x_current_display, rawkey, modifier, 1, + rawstring, strsize); + } + } + return Qnil; +} +#else +DEFUN ("x-rebind-key", Fx_rebind_key, Sx_rebind_key, 3, 3, 0, + "Rebind KEYCODE, with shift bits SHIFT-MASK, to new string NEWSTRING.\n\ +KEYCODE and SHIFT-MASK should be numbers representing the X keyboard code\n\ +and shift mask respectively. NEWSTRING is an arbitrary string of keystrokes.\n\ +If SHIFT-MASK is nil, then KEYCODE's key will be bound to NEWSTRING for\n\ +all shift combinations.\n\ +Shift Lock 1 Shift 2\n\ +Meta 4 Control 8\n\ +\n\ +For values of KEYCODE, see /usr/lib/Xkeymap.txt (remember that the codes\n\ +in that file are in octal!)\n\ +\n\ +NOTE: due to an X bug, this function will not take effect unless one has\n\ +a `~/.Xkeymap' file. (See the documentation for the `keycomp' program.)\n\ +This problem will be fixed in X version 11.") + + (keycode, shift_mask, newstring) + register Lisp_Object keycode; + register Lisp_Object shift_mask; + register Lisp_Object newstring; +{ + char *rawstring; + int keysym, rawshift; + int i, strsize; + + CHECK_NUMBER (keycode, 1); + if (!NULL (shift_mask)) + CHECK_NUMBER (shift_mask, 2); + CHECK_STRING (newstring, 3); + strsize = XSTRING (newstring)->size; + rawstring = (char *) xmalloc (strsize); + bcopy (XSTRING (newstring)->data, rawstring, strsize); + + keysym = ((unsigned) (XINT (keycode))) & 255; + + if (NULL (shift_mask)) + { + for (i = 0; i <= 15; i++) + XRebindCode (keysym, i<<11, rawstring, strsize); + } + else + { + rawshift = (((unsigned) (XINT (shift_mask))) & 15) << 11; + XRebindCode (keysym, rawshift, rawstring, strsize); + } + return Qnil; +} + +DEFUN ("x-rebind-keys", Fx_rebind_keys, Sx_rebind_keys, 2, 2, 0, + "Rebind KEYCODE to list of strings STRINGS.\n\ +STRINGS should be a list of 16 elements, one for each shift combination.\n\ +nil as element means don't change.\n\ +See the documentation of `x-rebind-key' for more information.") + (keycode, strings) + register Lisp_Object keycode; + register Lisp_Object strings; +{ + register Lisp_Object item; + register char *rawstring; + KeySym rawkey, modifier[1]; + int strsize; + register unsigned i; + + CHECK_NUMBER (keycode, 1); + CHECK_CONS (strings, 2); + rawkey = (KeySym) ((unsigned) (XINT (keycode))) & 255; + for (i = 0; i <= 15; strings = Fcdr (strings), i++) + { + item = Fcar (strings); + if (!NULL (item)) + { + CHECK_STRING (item, 2); + strsize = XSTRING (item)->size; + rawstring = (char *) xmalloc (strsize); + bcopy (XSTRING (item)->data, rawstring, strsize); + XRebindCode (rawkey, i << 11, rawstring, strsize); + } + } + return Qnil; +} +#endif /* not HAVE_X11 */ + +#ifdef HAVE_X11 +Visual * +select_visual (screen, depth) + Screen *screen; + unsigned int *depth; +{ + Visual *v; + XVisualInfo *vinfo, vinfo_template; + int n_visuals; + + v = DefaultVisualOfScreen (screen); + vinfo_template.visualid = XVisualIDFromVisual (v); + vinfo = XGetVisualInfo (x_current_display, VisualIDMask, &vinfo_template, + &n_visuals); + if (n_visuals != 1) + fatal ("Can't get proper X visual info"); + + if ((1 << vinfo->depth) == vinfo->colormap_size) + *depth = vinfo->depth; + else + { + int i = 0; + int n = vinfo->colormap_size - 1; + while (n) + { + n = n >> 1; + i++; + } + *depth = i; + } + + XFree ((char *) vinfo); + return v; +} +#endif /* HAVE_X11 */ + +DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection, + 1, 2, 0, "Open a connection to an X server.\n\ +DISPLAY is the name of the display to connect to. Optional second\n\ +arg XRM_STRING is a string of resources in xrdb format.") + (display, xrm_string) + Lisp_Object display, xrm_string; +{ + unsigned int n_planes; + register Screen *x_screen; + unsigned char *xrm_option; + + CHECK_STRING (display, 0); + if (x_current_display != 0) + error ("X server connection is already initialized"); + + /* This is what opens the connection and sets x_current_display. + This also initializes many symbols, such as those used for input. */ + x_term_init (XSTRING (display)->data); + + Qtext_part = intern ("text-part"); + Qmodeline_part = intern ("modeline-part"); + Qvscrollbar_part = intern ("vscrollbar-part"); + Qvslider_part = intern ("vslider-part"); + Qvthumbup_part = intern ("vthumbup-part"); + Qvthumbdown_part = intern ("vthumbdown-part"); + Qhscrollbar_part = intern ("hscrollbar-part"); + Qhslider_part = intern ("hslider-part"); + Qhthumbleft_part = intern ("hthumbleft-part"); + Qhthumbright_part = intern ("hthumbright-part"); + +#ifdef HAVE_X11 + XFASTINT (Vwindow_system_version) = 11; + + if (!EQ (xrm_string, Qnil)) + { + CHECK_STRING (xrm_string, 1); + xrm_option = (unsigned char *) XSTRING (xrm_string); + } + else + xrm_option = (unsigned char *) 0; + xrdb = x_load_resources (x_current_display, xrm_option, EMACS_CLASS); + x_current_display->db = xrdb; + + x_screen = DefaultScreenOfDisplay (x_current_display); + + x_screen_count = make_number (ScreenCount (x_current_display)); + Vx_vendor = build_string (ServerVendor (x_current_display)); + x_release = make_number (VendorRelease (x_current_display)); + + x_screen_height = make_number (HeightOfScreen (x_screen)); + x_screen_height_mm = make_number (HeightMMOfScreen (x_screen)); + x_screen_width = make_number (WidthOfScreen (x_screen)); + x_screen_width_mm = make_number (WidthMMOfScreen (x_screen)); + + switch (DoesBackingStore (x_screen)) + { + case Always: + Vx_backing_store = intern ("Always"); + break; + + case WhenMapped: + Vx_backing_store = intern ("WhenMapped"); + break; + + case NotUseful: + Vx_backing_store = intern ("NotUseful"); + break; + + default: + error ("Strange value for BackingStore."); + break; + } + + if (DoesSaveUnders (x_screen) == True) + x_save_under = Qt; + else + x_save_under = Qnil; + + screen_visual = select_visual (x_screen, &n_planes); + x_screen_planes = make_number (n_planes); + Vx_screen_visual = intern (x_visual_strings [screen_visual->class]); + + /* X Atoms used by emacs. */ + BLOCK_INPUT; + Xatom_emacs_selection = XInternAtom (x_current_display, "_EMACS_SELECTION_", + False); + Xatom_clipboard = XInternAtom (x_current_display, "CLIPBOARD", + False); + Xatom_clipboard_selection = XInternAtom (x_current_display, "_EMACS_CLIPBOARD_", + False); + Xatom_wm_change_state = XInternAtom (x_current_display, "WM_CHANGE_STATE", + False); + Xatom_incremental = XInternAtom (x_current_display, "INCR", + False); + Xatom_multiple = XInternAtom (x_current_display, "MULTIPLE", + False); + Xatom_targets = XInternAtom (x_current_display, "TARGETS", + False); + Xatom_timestamp = XInternAtom (x_current_display, "TIMESTAMP", + False); + Xatom_delete = XInternAtom (x_current_display, "DELETE", + False); + Xatom_insert_selection = XInternAtom (x_current_display, "INSERT_SELECTION", + False); + Xatom_pair = XInternAtom (x_current_display, "XA_ATOM_PAIR", + False); + Xatom_insert_property = XInternAtom (x_current_display, "INSERT_PROPERTY", + False); + Xatom_text = XInternAtom (x_current_display, "TEXT", + False); + UNBLOCK_INPUT; +#else /* not HAVE_X11 */ + XFASTINT (Vwindow_system_version) = 10; +#endif /* not HAVE_X11 */ + return Qnil; +} + +DEFUN ("x-close-current-connection", Fx_close_current_connection, + Sx_close_current_connection, + 0, 0, 0, "Close the connection to the current X server.") + () +{ +#ifdef HAVE_X11 + /* This is ONLY used when killing emacs; For switching displays + we'll have to take care of setting CloseDownMode elsewhere. */ + + if (x_current_display) + { + BLOCK_INPUT; + XSetCloseDownMode (x_current_display, DestroyAll); + XCloseDisplay (x_current_display); + } + else + fatal ("No current X display connection to close\n"); +#endif + return Qnil; +} + +DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, + 1, 1, 0, "If ON is non-nil, report X errors as soon as the erring request is made.\n\ +If ON is nil, allow buffering of requests.\n\ +Turning on synchronization prohibits the Xlib routines from buffering\n\ +requests and seriously degrades performance, but makes debugging much\n\ +easier.") + (on) + Lisp_Object on; +{ + XSynchronize (x_current_display, !EQ (on, Qnil)); + + return Qnil; +} + + +syms_of_xfns () +{ + init_x_parm_symbols (); + + /* This is zero if not using X windows. */ + x_current_display = 0; + + Qundefined_color = intern ("undefined-color"); + Fput (Qundefined_color, Qerror_conditions, + Fcons (Qundefined_color, Fcons (Qerror, Qnil))); + Fput (Qundefined_color, Qerror_message, + build_string ("Undefined color")); + + DEFVAR_INT ("mouse-x-position", &x_mouse_x, + "The X coordinate of the mouse position, in characters."); + x_mouse_x = Qnil; + + DEFVAR_INT ("mouse-y-position", &x_mouse_y, + "The Y coordinate of the mouse position, in characters."); + x_mouse_y = Qnil; + + DEFVAR_INT ("mouse-buffer-offset", &mouse_buffer_offset, + "The buffer offset of the character under the pointer."); + mouse_buffer_offset = Qnil; + + DEFVAR_LISP ("mouse-screen-part", &Vmouse_screen_part, + "A symbol indicating the part of the screen the mouse is in."); + Vmouse_screen_part = Qnil; + + DEFVAR_INT ("x-pointer-shape", &Vx_pointer_shape, + "The shape of the pointer when over text."); + Vx_pointer_shape = Qnil; + + DEFVAR_INT ("x-nontext-pointer-shape", &Vx_nontext_pointer_shape, + "The shape of the pointer when not over text."); + Vx_nontext_pointer_shape = Qnil; + + DEFVAR_INT ("x-mode-pointer-shape", &Vx_mode_pointer_shape, + "The shape of the pointer when not over text."); + Vx_mode_pointer_shape = Qnil; + + DEFVAR_LISP ("x-bar-cursor", &Vbar_cursor, + "*If non-nil, use a vertical bar cursor. Otherwise, use the traditional box."); + Vbar_cursor = Qnil; + + DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel, + "A string indicating the foreground color of the cursor box."); + Vx_cursor_fore_pixel = Qnil; + + DEFVAR_LISP ("mouse-grabbed", &Vmouse_depressed, + "Non-nil if a mouse button is currently depressed."); + Vmouse_depressed = Qnil; + + DEFVAR_INT ("x-screen-count", &x_screen_count, + "The number of screens associated with the current display."); + DEFVAR_INT ("x-release", &x_release, + "The release number of the X server in use."); + DEFVAR_LISP ("x-vendor", &Vx_vendor, + "The vendor supporting the X server in use."); + DEFVAR_INT ("x-screen-height", &x_screen_height, + "The height of this X screen in pixels."); + DEFVAR_INT ("x-screen-height-mm", &x_screen_height_mm, + "The height of this X screen in millimeters."); + DEFVAR_INT ("x-screen-width", &x_screen_width, + "The width of this X screen in pixels."); + DEFVAR_INT ("x-screen-width-mm", &x_screen_width_mm, + "The width of this X screen in millimeters."); + DEFVAR_LISP ("x-backing-store", &Vx_backing_store, + "The backing store capability of this screen.\n\ +Values can be the symbols Always, WhenMapped, or NotUseful."); + DEFVAR_BOOL ("x-save-under", &x_save_under, + "*Non-nil means this X screen supports the SaveUnder feature."); + DEFVAR_INT ("x-screen-planes", &x_screen_planes, + "The number of planes this monitor supports."); + DEFVAR_LISP ("x-screen-visual", &Vx_screen_visual, + "The default X visual for this X screen."); + DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager, + "t if no X window manager is in use."); + +#ifdef HAVE_X11 + defsubr (&Sx_get_resource); + defsubr (&Sx_pixel_width); + defsubr (&Sx_pixel_height); + defsubr (&Sx_draw_rectangle); + defsubr (&Sx_erase_rectangle); + defsubr (&Sx_contour_region); + defsubr (&Sx_uncontour_region); + defsubr (&Sx_color_display_p); + defsubr (&Sx_defined_color); +#if 0 + defsubr (&Sx_track_pointer); +#endif + defsubr (&Sx_grab_pointer); + defsubr (&Sx_ungrab_pointer); +#else + defsubr (&Sx_get_default); + defsubr (&Sx_store_cut_buffer); + defsubr (&Sx_get_cut_buffer); + defsubr (&Sx_set_face); +#endif + defsubr (&Sx_geometry); + defsubr (&Sx_create_screen); + defsubr (&Sfocus_screen); + defsubr (&Sunfocus_screen); + defsubr (&Sx_horizontal_line); + defsubr (&Sx_rebind_key); + defsubr (&Sx_rebind_keys); + defsubr (&Sx_open_connection); + defsubr (&Sx_close_current_connection); + defsubr (&Sx_synchronize); + + /* This was used in the old event interface which used a separate + event queue.*/ +#if 0 + defsubr (&Sx_mouse_events); + defsubr (&Sx_get_mouse_event); +#endif +} + +#endif /* HAVE_X_WINDOWS */