Mercurial > emacs
changeset 286:8a40ab4a424f
Initial revision
author | Jim Blandy <jimb@redhat.com> |
---|---|
date | Sat, 25 May 1991 06:46:10 +0000 |
parents | adb31fcccc2b |
children | 1616777eaae5 |
files | src/frame.c src/xterm.c |
diffstat | 2 files changed, 4854 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/frame.c Sat May 25 06:46:10 1991 +0000 @@ -0,0 +1,1056 @@ +/* Generic screen functions. + 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. */ + +#include "config.h" +#include "lisp.h" +#include "screen.h" +#include "window.h" + +Lisp_Object Vemacs_iconified; +Lisp_Object Qscreenp; +Lisp_Object Vscreen_list; +Lisp_Object Vterminal_screen; +Lisp_Object Vglobal_minibuffer_screen; + +extern Lisp_Object Vminibuffer_list; +extern Lisp_Object get_minibuffer (); + +DEFUN ("screenp", Fscreenp, Sscreenp, 1, 1, 0, + "Return non-nil if OBJECT is a screen.\n\ +Value is t for a termcap screen (a character-only terminal),\n\ +`x' for an Emacs screen that is really an X window.") + (screen) + Lisp_Object screen; +{ + if (XTYPE (screen) != Lisp_Screen) + return Qnil; + switch (XSCREEN (screen)->output_method) + { + case output_termcap: + return Qt; + case output_x_window: + return intern ("x"); + default: + abort (); + } +} + +struct screen * +make_screen (mini_p) + int mini_p; +{ + Lisp_Object screen; + register struct screen *s; + register Lisp_Object root_window; + register Lisp_Object mini_window; + + screen = Fmake_vector (sizeof (struct screen) - sizeof (Lisp_Vector) + 1, + make_number (0)); + XSETTYPE (screen, Lisp_Screen); + s = XSCREEN (screen); + + s->cursor_x = 0; + s->cursor_y = 0; + s->current_glyphs = 0; + s->desired_glyphs = 0; + s->visible = 0; + s->display.nothing = 0; + s->iconified = 0; + s->wants_modeline = 1; + s->auto_raise = 0; + s->auto_lower = 0; + s->no_split = 0; + s->garbaged = 0; + s->has_minibuffer = mini_p; + + s->param_alist = Qnil; + + root_window = make_window (0); + if (mini_p) + { + mini_window = make_window (0); + XWINDOW (root_window)->next = mini_window; + XWINDOW (mini_window)->prev = root_window; + XWINDOW (mini_window)->mini_p = Qt; + XWINDOW (mini_window)->screen = screen; + s->minibuffer_window = mini_window; + } + else + { + mini_window = Qnil; + XWINDOW (root_window)->next = Qnil; + s->minibuffer_window = Qnil; + } + + XWINDOW (root_window)->screen = screen; + + /* 10 is arbitrary, + just so that there is "something there." + Correct size will be set up later with change_screen_size. */ + + s->width = 10; + s->height = 10; + + XFASTINT (XWINDOW (root_window)->width) = 10; + XFASTINT (XWINDOW (root_window)->height) = (mini_p ? 9 : 10); + + if (mini_p) + { + XFASTINT (XWINDOW (mini_window)->width) = 10; + XFASTINT (XWINDOW (mini_window)->top) = 9; + XFASTINT (XWINDOW (mini_window)->height) = 1; + } + + XWINDOW (root_window)->buffer = Qt; + Fset_window_buffer (root_window, Fcurrent_buffer ()); + if (mini_p) + { + XWINDOW (mini_window)->buffer = Qt; + Fset_window_buffer (mini_window, + (NULL (Vminibuffer_list) + ? get_minibuffer (0) + : Fcar (Vminibuffer_list))); + } + + s->selected_window = root_window; + s->root_window = root_window; + + Vscreen_list = Fcons (screen, Vscreen_list); + + return s; +} + +/* Make a screen using a separate minibuffer window on another screen. + MINI_WINDOW is the minibuffer window to use. nil means use the + default (the global minibuffer). */ + +struct screen * +make_screen_without_minibuffer (mini_window) + register Lisp_Object mini_window; +{ + register struct screen *s; + + /* Choose the minibuffer window to use. */ + if (NULL (mini_window)) + { + CHECK_SCREEN (Vglobal_minibuffer_screen, 0); + mini_window = XSCREEN (Vglobal_minibuffer_screen)->minibuffer_window; + } + else + { + CHECK_WINDOW (mini_window, 0); + } + + /* Make a screen containing just a root window. */ + s = make_screen (0); + + /* Install the chosen minibuffer window, with proper buffer. */ + s->minibuffer_window = mini_window; + Fset_window_buffer (mini_window, + (NULL (Vminibuffer_list) + ? get_minibuffer (0) + : Fcar (Vminibuffer_list))); + return s; +} + +/* Make a screen containing only a minibuffer window. */ + +struct screen * +make_minibuffer_screen () +{ + /* First make a screen containing just a root window, no minibuffer. */ + + register struct screen *s = make_screen (0); + register Lisp_Object mini_window; + register Lisp_Object screen; + + XSET (screen, Lisp_Screen, s); + + /* ??? Perhaps leave it to the user program to set auto_raise. */ + s->auto_raise = 1; + s->auto_lower = 0; + s->no_split = 1; + s->wants_modeline = 0; + /* Note we leave has_minibuffer as 0. This is a little strange. */ + + /* Now label the root window as also being the minibuffer. + Avoid infinite looping on the window chain by marking next pointer + as nil. */ + + mini_window = s->minibuffer_window = s->root_window; + XWINDOW (mini_window)->mini_p = Qt; + XWINDOW (mini_window)->next = Qnil; + XWINDOW (mini_window)->prev = mini_window; + XWINDOW (mini_window)->screen = screen; + + /* Put the proper buffer in that window. */ + + Fset_window_buffer (mini_window, + (NULL (Vminibuffer_list) + ? get_minibuffer (0) + : Fcar (Vminibuffer_list))); + return s; +} + +/* Construct a screen that refers to the terminal (stdin and stdout). */ + +struct screen * +make_terminal_screen () +{ + register struct screen *s; + + Vscreen_list = Qnil; + s = make_screen (1); + s->name = build_string ("terminal"); + s->visible = 1; + s->display.nothing = 1; /* Nonzero means screen isn't deleted. */ + XSET (Vterminal_screen, Lisp_Screen, s); + return s; +} + +DEFUN ("select-screen", Fselect_screen, Sselect_screen, 1, 2, 0, + "Select the screen S. S's selected window becomes \"the\"\n\ +selected window. If the optional parameter NO-ENTER is non-nil, don't +focus on that screen.") + (screen, no_enter) + Lisp_Object screen, no_enter; +{ + CHECK_SCREEN (screen, 0); + + if (selected_screen == XSCREEN (screen)) + return screen; + + selected_screen = XSCREEN (screen); + Fselect_window (XSCREEN (screen)->selected_window); + +#ifdef HAVE_X_WINDOWS +#ifdef MULTI_SCREEN + if (XSCREEN (screen)->output_method == output_x_window + && NULL (no_enter)) + { + Ffocus_screen (screen); + } +#endif +#endif + choose_minibuf_screen (); + + return screen; +} + +DEFUN ("selected-screen", Fselected_screen, Sselected_screen, 0, 0, 0, + "Return the screen that is now selected.") + () +{ + Lisp_Object tem; + XSET (tem, Lisp_Screen, selected_screen); + return tem; +} + +DEFUN ("window-screen", Fwindow_screen, Swindow_screen, 1, 1, 0, + "Return the screen object that window WINDOW is on.") + (window) + Lisp_Object window; +{ + CHECK_WINDOW (window, 0); + return XWINDOW (window)->screen; +} + +DEFUN ("screen-root-window", Fscreen_root_window, Sscreen_root_window, 0, 1, 0, + "Returns the root-window of SCREEN.") + (screen) + Lisp_Object screen; +{ + if (NULL (screen)) + XSET (screen, Lisp_Screen, selected_screen); + CHECK_SCREEN (screen, 0); + + return XSCREEN (screen)->root_window; +} + +DEFUN ("screen-selected-window", Fscreen_selected_window, + Sscreen_selected_window, 0, 1, 0, + "Return the selected window of screen object SCREEN.") + (screen) + Lisp_Object screen; +{ + if (NULL (screen)) + XSET (screen, Lisp_Screen, selected_screen); + CHECK_SCREEN (screen, 0); + + return XSCREEN (screen)->selected_window; +} + +DEFUN ("screen-list", Fscreen_list, Sscreen_list, + 0, 0, 0, + "Return a list of all screens.") + () +{ + return Fcopy_sequence (Vscreen_list); +} + +#ifdef MULTI_SCREEN +Lisp_Object +next_screen (screen, mini_screen) + Lisp_Object screen; + int mini_screen; +{ + Lisp_Object tail; + int passed = 0; + + while (1) + for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr) + { + if (passed) + if (!mini_screen + && EQ (XCONS (tail)->car, Vglobal_minibuffer_screen)) + continue; + else + return XCONS (tail)->car; + + if (EQ (screen, XCONS (tail)->car)) + passed++; + } +} + +Lisp_Object +prev_screen (screen, mini_screen) + Lisp_Object screen; + int mini_screen; +{ + Lisp_Object tail; + Lisp_Object prev; + + prev = Qnil; + while (1) + for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr) + { + if (EQ (screen, XCONS (tail)->car)) + { + if (!NULL (prev) && (mini_screen + || !EQ (XCONS (tail)->car, + Vglobal_minibuffer_screen))) + return prev; + } + prev = XCONS (tail)->car; + } +} + +DEFUN ("next-screen", Fnext_screen, Snext_screen, + 0, 2, 0, + "Return the next screen in the screen list after SCREEN.\n\ +If MINISCREEN is non-nil, include the global-minibuffer-screen if it\n\ +has its own screen.") + (screen, miniscreen) +Lisp_Object screen, miniscreen; +{ + Lisp_Object tail; + + if (NULL (screen)) + XSET (screen, Lisp_Screen, selected_screen); + CHECK_SCREEN (screen, 0); + + return next_screen (screen, (NULL (miniscreen) ? 0 : 1)); +} +#endif /* MULTI_SCREEN */ + +DEFUN ("delete-screen", Fdelete_screen, Sdelete_screen, + 0, 1, "", + "Delete SCREEN, permanently eliminating it from use.\n\ +Default is current screen.") + (screen) + Lisp_Object screen; +{ + struct screen *s; + union display displ; + + if (EQ (screen, Qnil)) + { + s = selected_screen; + XSET (screen, Lisp_Screen, s); + } + else + { + CHECK_SCREEN (screen, 0); + s = XSCREEN (screen); + } + + /* Don't allow deleted screen to remain selected. */ + if (s == selected_screen) + { + Lisp_Object next; + + next = next_screen (screen, 0); + if (EQ (next, screen)) + error ("Attempt to delete the only screen"); + Fselect_screen (next, Qnil); + } + + /* Don't allow the global minibuffer screen to be deleted */ + if (s == XSCREEN (Vglobal_minibuffer_screen)) + error ("Attempt to delete the global minibuffer screen"); + + /* Don't allow minibuf_window to remain on a deleted screen. */ + if (EQ (s->minibuffer_window, minibuf_window)) + { + Fset_window_buffer (selected_screen->minibuffer_window, + XWINDOW (minibuf_window)->buffer); + minibuf_window = selected_screen->minibuffer_window; + } + + Vscreen_list = Fdelq (screen, Vscreen_list); + s->visible = 0; + displ = s->display; + s->display.nothing = 0; + + if (s->output_method == output_x_window) + x_destroy_window (s, displ); + + return Qnil; +} + +/* Return mouse position in character cell units. */ + +static +read_mouse_position (screen, x, y) + Lisp_Object screen; + int *x, *y; +{ + CHECK_SCREEN (screen, 0); + + *x = 1; + *y = 1; + +#ifdef HAVE_X_WINDOWS + if (XSCREEN (screen)->output_method == output_x_window) + x_read_mouse_position (XSCREEN (screen), x, y); +#endif +} + +DEFUN ("read-mouse-position", Fread_mouse_position, Sread_mouse_position, 1, 1, 0, + "Return a cons (x . y) which represents the position of the mouse.") + (screen) + Lisp_Object screen; +{ + int x, y; + struct screen *s; + + CHECK_SCREEN (screen, 0); + + read_mouse_position (screen, &x, &y); + return Fcons (make_number (x), make_number (y)); +} + +DEFUN ("set-mouse-position", Fset_mouse_position, Sset_mouse_position, 3, 3, 0, + "Move the mouse pointer to the center of cell (X,Y) in SCREEN.\n\ +WARNING: If you use this under X, you should do unfocus-screen afterwards.") + (screen, x, y) + Lisp_Object screen, x, y; +{ + CHECK_SCREEN (screen, 0); + CHECK_NUMBER (x, 2); + CHECK_NUMBER (y, 1); + +#ifdef HAVE_X_WINDOWS + if (XSCREEN (screen)->output_method == output_x_window) + /* Warping the mouse will cause enternotify and focus events. */ + x_set_mouse_position (XSCREEN (screen), x, y); +#endif + + return Qnil; +} + +#if 0 +/* ??? Can this be replaced with a Lisp function? + It is used in minibuf.c. Can we get rid of that? */ + +DEFUN ("screen-configuration", Fscreen_configuration, Sscreen_configuration, + 0, 0, 0, + "Return object describing current screen configuration.\n\ +The screen configuration is the current mouse position and selected screen.\n\ +This object can be given to `restore-screen-configuration'\n\ +to restore this screen configuration.") + () +{ + int x, y; + Lisp_Object c, screen; + struct screen *s; + + c = Fmake_vector (make_number(3), Qnil); + XVECTOR (c)->contents[0] = screen = Fselected_screen(); + read_mouse_position (screen, &x, &y); + XVECTOR (c)->contents[1] = make_number (x); + XVECTOR (c)->contents[2] = make_number (y); + + return c; +} + +DEFUN ("restore-screen-configuration", Frestore_screen_configuration, + Srestore_screen_configuration, + 1, 1, 0, + "Restores screen configuration CONFIGURATION.") + (config) + Lisp_Object config; +{ + Lisp_Object x_pos, y_pos, screen; + + CHECK_VECTOR (config, 0); + if (XVECTOR (config)->size != 3) + { + error ("Wrong size vector passed to restore-screen-configuration"); + } + screen = XVECTOR (config)->contents[0]; + CHECK_SCREEN (screen, 0); + + Fselect_screen (screen, Qnil); + +#if 0 + /* This seems to interfere with the screen selection mechanism. jla */ + x_pos = XVECTOR (config)->contents[1]; + y_pos = XVECTOR (config)->contents[2]; + set_mouse_position (screen, XINT (x_pos), XINT (y_pos)); +#endif + + return screen; +} +#endif + +DEFUN ("make-screen-visible", Fmake_screen_visible, Smake_screen_visible, + 1, 1, 0, + "Make the screen SCREEN visible (assuming it is an X-window).\n\ +Also raises the screen so that nothing obscures it.") + (screen) + Lisp_Object screen; +{ + CHECK_SCREEN (screen, 0); + + if (XSCREEN (screen)->display.nothing == 0) + error ("Cannot make a dead screen object visible"); + + if (XSCREEN (screen)->output_method == output_x_window) + x_make_screen_visible (XSCREEN (screen)); + + return screen; +} + +DEFUN ("make-screen-invisible", Fmake_screen_invisible, Smake_screen_invisible, + 1, 1, 0, + "Make the screen SCREEN invisible (assuming it is an X-window).") + (screen) + Lisp_Object screen; +{ + CHECK_SCREEN (screen, 0); + + if (XSCREEN (screen)->output_method == output_x_window) + x_make_screen_invisible (XSCREEN (screen)); + + return Qnil; +} + +DEFUN ("iconify-screen", Ficonify_screen, Siconify_screen, + 1, 1, 0, + "Make the screen SCREEN into an icon.") + (screen) + Lisp_Object screen; +{ + CHECK_SCREEN (screen, 0); + + if (XSCREEN (screen)->display.nothing == 0) + error ("Cannot make a dead screen object iconified."); + + if (XSCREEN (screen)->output_method == output_x_window) + x_iconify_screen (XSCREEN (screen)); + + return Qnil; +} + +DEFUN ("deiconify-screen", Fdeiconify_screen, Sdeiconify_screen, + 1, 1, 0, + "Open (de-iconify) the iconified screen SCREEN.") + (screen) + Lisp_Object screen; +{ + CHECK_SCREEN (screen, 0); + + if (XSCREEN (screen)->display.nothing == 0) + error ("Cannot deiconify a dead screen object."); + + if (XSCREEN (screen)->output_method == output_x_window) + x_make_screen_visible (XSCREEN (screen)); + + return screen; +} + +DEFUN ("screen-visible-p", Fscreen_visible_p, Sscreen_visible_p, + 1, 1, 0, + "Return t if SCREEN is now \"visible\" (actually in use for display).\n\ +A screen that is not \"visible\" is not updated and, if it works through\n\ +a window system, it may not show at all.\n\ +Return the symbol `icon' if window is visible only as an icon.") + (screen) + Lisp_Object screen; +{ + CHECK_SCREEN (screen, 0); + + if (XSCREEN (screen)->visible) + return Qt; + if (XSCREEN (screen)->iconified) + return intern ("icon"); + return Qnil; +} + +DEFUN ("visible-screen-list", Fvisible_screen_list, Svisible_screen_list, + 0, 0, 0, + "Return a list of all screens now \"visible\" (being updated).") + () +{ + Lisp_Object tail, screen; + struct screen *s; + Lisp_Object value; + + value = Qnil; + 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->visible) + value = Fcons (screen, value); + } + return value; +} + +Lisp_Object +get_screen_param (screen, prop) + register struct screen *screen; + Lisp_Object prop; +{ + register Lisp_Object tem; + + tem = Fassq (prop, screen->param_alist); + if (EQ (tem, Qnil)) + return tem; + return Fcdr (tem); +} + +void +store_in_alist (alistptr, propname, val) + Lisp_Object *alistptr, val; + char *propname; +{ + register Lisp_Object tem; + register Lisp_Object prop; + + prop = intern (propname); + tem = Fassq (prop, *alistptr); + if (EQ (tem, Qnil)) + *alistptr = Fcons (Fcons (prop, val), *alistptr); + else + Fsetcdr (tem, val); +} + +void +store_screen_param (s, prop, val) + struct screen *s; + Lisp_Object prop, val; +{ + register Lisp_Object tem; + + tem = Fassq (prop, s->param_alist); + if (EQ (tem, Qnil)) + s->param_alist = Fcons (Fcons (prop, val), s->param_alist); + else + Fsetcdr (tem, val); +} + +DEFUN ("screen-parameters", Fscreen_parameters, Sscreen_parameters, 0, 1, 0, + "Return the parameters-alist of screen SCREEN.\n\ +It is a list of elements of the form (PARM . VALUE), where PARM is a symbol.\n\ +The meaningful PARMs depend on the kind of screen.") + (screen) + Lisp_Object screen; +{ + Lisp_Object alist; + struct screen *s; + + if (EQ (screen, Qnil)) + s = selected_screen; + else + { + CHECK_SCREEN (screen, 0); + s = XSCREEN (screen); + } + + if (s->display.nothing == 0) + return Qnil; + + alist = Fcopy_alist (s->param_alist); + store_in_alist (&alist, "name", s->name); + store_in_alist (&alist, "height", make_number (s->height)); + store_in_alist (&alist, "width", make_number (s->width)); + store_in_alist (&alist, "modeline", (s->wants_modeline ? Qt : Qnil)); + store_in_alist (&alist, "minibuffer", (s->has_minibuffer ? Qt : Qnil)); + store_in_alist (&alist, "unsplittable", (s->no_split ? Qt : Qnil)); + + if (s->output_method == output_x_window) + x_report_screen_params (s, &alist); + return alist; +} + +DEFUN ("modify-screen-parameters", Fmodify_screen_parameters, + Smodify_screen_parameters, 2, 2, 0, + "Modify the parameters of screen SCREEN according to ALIST.\n\ +ALIST is an alist of parameters to change and their new values.\n\ +Each element of ALIST has the form (PARM . VALUE), where PARM is a symbol.\n\ +The meaningful PARMs depend on the kind of screen; undefined PARMs are ignored.") + (screen, alist) + Lisp_Object screen, alist; +{ + register struct screen *s; + register Lisp_Object tail, elt, prop, val; + + if (EQ (screen, Qnil)) + s = selected_screen; + else + { + CHECK_SCREEN (screen, 0); + s = XSCREEN (screen); + } + + if (s->display.nothing == 0) + error ("Cannot modify parameters of a deleted screen"); + + if (s->output_method == output_x_window) + for (tail = alist; !EQ (tail, Qnil); tail = Fcdr (tail)) + { + elt = Fcar (tail); + prop = Fcar (elt); + val = Fcdr (elt); + x_set_screen_param (s, prop, val, + get_screen_param (s, prop)); + store_screen_param (s, prop, val); + } + + return Qnil; +} + + +DEFUN ("screen-pixel-size", Fscreen_pixel_size, + Sscreen_pixel_size, 1, 1, 0, + "Return a cons (width . height) of screen SCREEN's dimensions.") + (screen) + Lisp_Object screen; +{ + register struct screen *s; + int width, height; + + CHECK_SCREEN (screen, 0); + s = XSCREEN (screen); + + return Fcons (make_number (x_pixel_width (s)), + make_number (x_pixel_height (s))); +} + +DEFUN ("screen-height", Fscreen_height, Sscreen_height, 0, 0, 0, + "Return number of lines available for display on selected screen.") + () +{ + return make_number (SCREEN_HEIGHT (selected_screen)); +} + +DEFUN ("screen-width", Fscreen_width, Sscreen_width, 0, 0, 0, + "Return number of columns available for display on selected screen.") + () +{ + return make_number (SCREEN_WIDTH (selected_screen)); +} + +DEFUN ("set-screen-height", Fset_screen_height, Sset_screen_height, 2, 3, 0, + "Specify that the screen SCREEN has LINES lines.\n\ +Optional third arg non-nil means that redisplay should use LINES lines\n\ +but that the idea of the actual height of the screen should not be changed.") + (screen, rows, pretend) + Lisp_Object rows, pretend; +{ + register struct screen *s; + + CHECK_NUMBER (rows, 0); + if (NULL (screen)) + s = selected_screen; + else + { + CHECK_SCREEN (screen, 0); + s = XSCREEN (screen); + } + + if (s->output_method == output_x_window) + { + if (XINT (rows) != s->width) + x_set_window_size (s, s->width, XINT (rows)); + } + else + change_screen_size (s, XINT (rows), 0, !NULL (pretend)); + return Qnil; +} + +DEFUN ("set-screen-width", Fset_screen_width, Sset_screen_width, 2, 3, 0, + "Specify that the screen SCREEN has COLS columns.\n\ +Optional third arg non-nil means that redisplay should use COLS columns\n\ +but that the idea of the actual width of the screen should not be changed.") + (screen, cols, pretend) + Lisp_Object cols, pretend; +{ + register struct screen *s; + CHECK_NUMBER (cols, 0); + if (NULL (screen)) + s = selected_screen; + else + { + CHECK_SCREEN (screen, 0); + s = XSCREEN (screen); + } + + if (s->output_method == output_x_window) + { + if (XINT (cols) != s->width) + x_set_window_size (s, XINT (cols), s->height); + } + else + change_screen_size (selected_screen, 0, XINT (cols), !NULL (pretend)); + return Qnil; +} + +DEFUN ("set-screen-size", Fset_screen_size, + Sset_screen_size, 3, 3, 0, + "Sets size of SCREEN to COLS by ROWS, measured in characters.") + (screen, cols, rows) + Lisp_Object screen, cols, rows; +{ + register struct screen *s; + int mask; + + CHECK_SCREEN (screen, 0); + CHECK_NUMBER (cols, 2); + CHECK_NUMBER (rows, 1); + s = XSCREEN (screen); + + if (s->output_method == output_x_window) + { + if (XINT (rows) != s->height || XINT (cols) != s->width) + x_set_window_size (s, XINT (cols), XINT (rows)); + } + else + change_screen_size (s, XINT (rows), XINT (cols), 0); + + return Qnil; +} + +DEFUN ("set-screen-position", Fset_screen_position, + Sset_screen_position, 3, 3, 0, + "Sets size of SCREEN in pixels to XOFFSET by YOFFSET.") + (screen, xoffset, yoffset) + Lisp_Object screen, xoffset, yoffset; +{ + register struct screen *s; + int mask; + + CHECK_SCREEN (screen, 0); + CHECK_NUMBER (xoffset, 1); + CHECK_NUMBER (yoffset, 2); + s = XSCREEN (screen); + + if (s->output_method == output_x_window) + x_set_offset (s, XINT (xoffset), XINT (yoffset)); + + return Qt; +} + +/* Test if column *x, row *y is within window *w. If they are not, + return 0; if they are on the window's modeline, return -1; if + they are in the window's text area (the only other alternative) + set *x and *y to their locations relative to the upper left + corner of the window, and return 1. */ +int +coordinates_in_window (w, x, y) + register struct window *w; + register int *x, *y; +{ + register int left = XINT (w->left); + register int width = XINT (w->width); + register int screen_height = XINT ((XSCREEN (w->screen)->height)); + register int window_height = XINT (w->height); + register int top = XFASTINT (w->top); + + if (*x < left || *x >= left + width + || *y == screen_height || *y < top || *y > top + window_height - 1) + return 0; + + if (*y == top + window_height - 1 + && window_height > 1) /* 1 line => minibuffer */ + /* in modeline */ + return -1; + + *x -= left; + *y -= top; + return 1; +} + +DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p, + Scoordinates_in_window_p, 2, 2, 0, + "Return non-nil if COORDINATES are in WINDOW.\n\ +COORDINATES is a cons of the form (X Y), X and Y being screen-relative.\n\ +If COORDINATES are in the text portion of WINDOW, the coordinates relative\n\ +to the window are returned. If they are in the modeline of WINDOW, t is\n\ +returned.") + (coordinates, window) + register Lisp_Object coordinates, window; +{ + int x, y; + + CHECK_WINDOW (window, 0); + CHECK_CONS (coordinates, 1); + x = XINT (Fcar (coordinates)); + y = XINT (Fcar (Fcdr (coordinates))); + + switch (coordinates_in_window (XWINDOW (window), &x, &y)) + { + case -1: /* In modeline of window. */ + return Qt; + + case 0: /* NOT in window at all. */ + return Qnil; + + case 1: /* In text part of window. */ + return Fcons (x, Fcons (y, Qnil)); + + default: + abort (); + } +} + +#ifndef HAVE_X11 +DEFUN ("rubber-band-rectangle", Frubber_band_rectangle, Srubber_band_rectangle, + 3, 3, "", + "Ask user to specify a window position and size on SCREEN with the mouse.\n\ +Arguments are SCREEN, NAME and GEO. NAME is a name to be displayed as\n\ +the purpose of this rectangle. GEO is an X-windows size spec that can\n\ +specify defaults for some sizes/positions. If GEO specifies everything,\n\ +the mouse is not used.\n\ +Returns a list of five values: (SCREEN LEFT TOP WIDTH HEIGHT).") + (screen, name, geo) + Lisp_Object screen; + Lisp_Object name; + Lisp_Object geo; +{ + int vals[4]; + Lisp_Object nums[4]; + int i; + + CHECK_SCREEN (screen, 0); + CHECK_STRING (name, 1); + CHECK_STRING (geo, 2); + + switch (XSCREEN (screen)->output_method) + { + case output_x_window: + x_rubber_band (XSCREEN (screen), &vals[0], &vals[1], &vals[2], &vals[3], + XSTRING (geo)->data, XSTRING (name)->data); + break; + + default: + return Qnil; + } + + for (i = 0; i < 4; i++) + XFASTINT (nums[i]) = vals[i]; + return Fcons (screen, Flist (4, nums)); + return Qnil; +} +#endif /* not HAVE_X11 */ + +choose_minibuf_screen () +{ + /* For lowest-level minibuf, put it on currently selected screen + if screen has a minibuffer. */ + if (minibuf_level == 0 + && selected_screen != 0 + && !EQ (minibuf_window, selected_screen->minibuffer_window) + && !EQ (Qnil, selected_screen->minibuffer_window)) + { + Fset_window_buffer (selected_screen->minibuffer_window, + XWINDOW (minibuf_window)->buffer); + minibuf_window = selected_screen->minibuffer_window; + } +} + +syms_of_screen () +{ + Qscreenp = intern ("screenp"); + + staticpro (&Vscreen_list); + + DEFVAR_LISP ("terminal-screen", &Vterminal_screen, + "The initial screen-object, which represents Emacs's stdout."); + + DEFVAR_LISP ("emacs-iconified", &Vemacs_iconified, + "Non-nil if all of emacs is iconified and not screen updates are needed."); + Vemacs_iconified = Qnil; + + DEFVAR_LISP ("global-minibuffer-screen", &Vglobal_minibuffer_screen, + "A screen whose minibuffer is used by minibufferless screens.\n\ +When you create a minibufferless screen, by default it will use the\n\ +minibuffer of this screen. It is up to you to create a suitable screen\n\ +and store it in this variable."); + Vglobal_minibuffer_screen = Qnil; + + defsubr (&Sscreenp); + defsubr (&Sselect_screen); + defsubr (&Sselected_screen); + defsubr (&Swindow_screen); + defsubr (&Sscreen_root_window); + defsubr (&Sscreen_selected_window); + defsubr (&Sscreen_list); + defsubr (&Snext_screen); + defsubr (&Sdelete_screen); + defsubr (&Sread_mouse_position); + defsubr (&Sset_mouse_position); +#if 0 + defsubr (&Sscreen_configuration); + defsubr (&Srestore_screen_configuration); +#endif + defsubr (&Smake_screen_visible); + defsubr (&Smake_screen_invisible); + defsubr (&Siconify_screen); + defsubr (&Sdeiconify_screen); + defsubr (&Sscreen_visible_p); + defsubr (&Svisible_screen_list); + defsubr (&Sscreen_parameters); + defsubr (&Smodify_screen_parameters); + defsubr (&Sscreen_pixel_size); + defsubr (&Sscreen_height); + defsubr (&Sscreen_width); + defsubr (&Sset_screen_height); + defsubr (&Sset_screen_width); + defsubr (&Sset_screen_size); + defsubr (&Sset_screen_position); + defsubr (&Scoordinates_in_window_p); +#ifndef HAVE_X11 + defsubr (&Srubber_band_rectangle); +#endif /* HAVE_X11 */ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/xterm.c Sat May 25 06:46:10 1991 +0000 @@ -0,0 +1,3798 @@ +/* X Communication module for terminals which understand the X protocol. + Copyright (C) 1989 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Serious problems: + + Kludge: dup2 is used to put the X-connection socket into desc # 0 + so that wait_reading_process_input will wait for it in place of + actual terminal input. + +*/ + +#include "config.h" + +#ifdef HAVE_X_WINDOWS + +#include "lisp.h" +#undef NULL + +/* On 4.3 this loses if it comes after xterm.h. */ +#include <signal.h> + +/* This may include sys/types.h, and that somehow loses + if this is not done before the other system files. */ +#include "xterm.h" + +/* Load sys/types.h if not already loaded. + In some systems loading it twice is suicidal. */ +#ifndef makedev +#include <sys/types.h> +#endif + +#ifdef BSD +#include <sys/ioctl.h> +#include <strings.h> +#else +#include <sys/termio.h> +#include <string.h> +#endif + +/* Allow m- file to inhibit use of FIONREAD. */ +#ifdef BROKEN_FIONREAD +#undef FIONREAD +#endif + +/* We are unable to use interrupts if FIONREAD is not available, + so flush SIGIO so we won't try. */ +#ifndef FIONREAD +#ifdef SIGIO +#undef SIGIO +#endif +#endif + +#ifdef NEED_TIME_H +#include <time.h> +#else /* not NEED_TIME_H */ +#ifdef HAVE_TIMEVAL +#include <sys/time.h> +#endif /* HAVE_TIMEVAL */ +#endif /* not NEED_TIME_H */ + +#include <fcntl.h> +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <setjmp.h> +#include <sys/stat.h> +#include <sys/param.h> + +#include "dispextern.h" +#include "termhooks.h" +#include "termopts.h" +#include "termchar.h" +#if 0 +#include "sink.h" +#include "sinkmask.h" +#endif +#include "gnu.h" +#include "screen.h" +#include "disptab.h" +#include "window.h" +#include "buffer.h" +#include "xfns.h" + +#ifdef HAVE_X11 +#define XMapWindow XMapRaised /* Raise them when mapping. */ +#else +#include <X/Xkeyboard.h> +/*#include <X/Xproto.h> */ +#endif /* HAVE_X11 */ + +/* For sending Meta-characters. Do we need this? */ +#define METABIT 0200 + +#define min(a,b) ((a)<(b) ? (a) : (b)) +#define max(a,b) ((a)>(b) ? (a) : (b)) + +/* Nonzero means we must reprint all windows + because 1) we received an ExposeWindow event + or 2) we received too many ExposeRegion events to record. */ + +static int expose_all_windows; + +/* Nonzero means we must reprint all icon windows. */ + +static int expose_all_icons; + +#ifndef HAVE_X11 +/* ExposeRegion events, when received, are copied into this queue + for later processing. */ + +static struct event_queue x_expose_queue; + +/* ButtonPressed and ButtonReleased events, when received, + are copied into this queue for later processing. */ + +struct event_queue x_mouse_queue; +#endif + +/* Nonzero after BLOCK_INPUT; prevents input events from being + processed until later. */ + +int x_input_blocked; + +#if defined (SIGIO) && defined (FIONREAD) +int BLOCK_INPUT_mask; +#endif + +/* Nonzero if input events came in while x_input_blocked was nonzero. + UNBLOCK_INPUT checks for this. */ + +int x_pending_input; + +/* Nonzero if in redisplay (); prevents us from calling it recursively */ + +int in_display; + +/* The id of a bitmap used for icon windows. + One such map is shared by all Emacs icon windows. + This is zero if we have not yet had a need to create the bitmap. */ + +static Bitmap icon_bitmap; + +/* Font used for text icons. */ + +static FONT_TYPE *icon_font_info; + +/* Stuff for dealing with the main icon title. */ + +extern Lisp_Object Vcommand_line_args; +char *hostname, *id_name, *invocation_name; + +/* This is the X connection that we are using. */ + +Display *x_current_display; + +/* Screen being updated by update_screen. */ +/* This is set by XTupdate_begin and looked at by all the + XT functions. It is zero while not inside an update. + In that case, the XT functions assume that `selected_screen' + is the screen to apply to. */ + +static struct screen *updating_screen; + +/* The screen (if any) which has the X window that has keyboard focus. + Zero if none. This is examined by Ffocus_screen in screen.c */ + +struct screen *x_focus_screen; + +/* From .Xdefaults, the value of "emacs.WarpMouse". If non-zero, + mouse is moved to inside of screen when screen is de-iconified. */ + +static int warp_mouse_on_deiconify; + +/* During an update, maximum vpos for ins/del line operations to affect. */ + +static int flexlines; + +/* During an update, nonzero if chars output now should be highlighted. */ + +static int highlight; + +/* Nominal cursor position -- where to draw output. + During an update, these are different from the cursor-box position. */ + +static int curs_x; +static int curs_y; + +#ifdef HAVE_X11 +/* `t' if a mouse button is depressed. */ + +extern Lisp_Object Vmouse_depressed; + +/* Tells if a window manager is present or not. */ + +extern Lisp_Object Vx_no_window_manager; + +/* Timestamp that we requested selection data was made. */ +extern Time requestor_time; + +/* ID of the window requesting selection data. */ +extern Window requestor_window; + +/* Nonzero enables some debugging for the X interface code. */ +extern int _Xdebug; + +#else /* X10 stuff */ + +/* Bit patterns for the mouse cursor. */ + +short MouseCursor[] = { + 0x0000, 0x0008, 0x0018, 0x0038, + 0x0078, 0x00f8, 0x01f8, 0x03f8, + 0x07f8, 0x00f8, 0x00d8, 0x0188, + 0x0180, 0x0300, 0x0300, 0x0000}; + +short MouseMask[] = { + 0x000c, 0x001c, 0x003c, 0x007c, + 0x00fc, 0x01fc, 0x03fc, 0x07fc, + 0x0ffc, 0x0ffc, 0x01fc, 0x03dc, + 0x03cc, 0x0780, 0x0780, 0x0300}; + +static short grey_bits[] = { + 0x0005, 0x000a, 0x0005, 0x000a}; + +static Pixmap GreyPixmap = 0; +#endif /* X10 stuff */ + +/* From time to time we get info on an Emacs window, here. */ + +static WINDOWINFO_TYPE windowinfo; + +extern int errno; + +extern Lisp_Object Vglobal_minibuffer_screen; + +extern Display *XOpenDisplay (); +extern Window XCreateWindow (); + +extern Cursor XCreateCursor (); +extern FONT_TYPE *XOpenFont (); + +static void flashback (); + +#ifndef HAVE_X11 +static void dumpqueue (); +#endif + +void dumpborder (); +static XTcursor_to (); +static XTclear_end_of_line (); + +/* These hooks are called by update_screen at the beginning and end + of a screen update. We record in `updating_screen' the identity + of the screen being updated, so that the XT... functions do not + need to take a screen as argument. Most of the XT... functions + should never be called except during an update, the only exceptions + being XTcursor_to, XTwrite_char and XTreassert_line_highlight. */ + +extern int mouse_track_top, mouse_track_left, mouse_track_width; + +static +XTupdate_begin (s) + struct screen *s; +{ + int mask; + + if (s == 0) + abort (); + + updating_screen = s; + flexlines = s->height; + highlight = 0; + +#if 0 + if (mouse_track_width != 0) + { + x_rectangle (s, s->display.x->reverse_gc, + mouse_track_top, mouse_track_left, mouse_track_width, 1); + mouse_track_width = 0; + } +#endif + BLOCK_INPUT; +#ifndef HAVE_X11 + dumpqueue (); +#endif + UNBLOCK_INPUT; +} + +static void x_do_pending_expose (); + +static +XTupdate_end (s) + struct screen *s; +{ + int mask; + + if (updating_screen == 0 + || updating_screen != s) + abort (); + + BLOCK_INPUT; +#ifndef HAVE_X11 + dumpqueue (); +#endif + adjust_scrollbars (s); + x_do_pending_expose (); + + x_display_cursor (s, 1); + + updating_screen = 0; + XFlushQueue (); + UNBLOCK_INPUT; +} + +/* External interface to control of standout mode. + Call this when about to modify line at position VPOS + and not change whether it is highlighted. */ + +XTreassert_line_highlight (new, vpos) + int new, vpos; +{ + highlight = new; +} + +/* Call this when about to modify line at position VPOS + and change whether it is highlighted. */ + +static +XTchange_line_highlight (new_highlight, vpos, first_unused_hpos) + int new_highlight, vpos, first_unused_hpos; +{ + highlight = new_highlight; + XTcursor_to (vpos, 0); + XTclear_end_of_line (updating_screen->width); +} + +/* This is used when starting Emacs and when restarting after suspend. + When starting Emacs, no X window is mapped. And nothing must be done + to Emacs's own window if it is suspended (though that rarely happens). */ + +static +XTset_terminal_modes () +{ +} + +/* This is called when exiting or suspending Emacs. + Exiting will make the X-windows go away, and suspending + requires no action. */ + +static +XTreset_terminal_modes () +{ +/* XTclear_screen (); */ +} + +/* Set the nominal cursor position of the screen: + where display update commands will take effect. + This does not affect the place where the cursor-box is displayed. */ + +XTcursor_to (row, col) + register int row, col; +{ + int mask; + int orow = row; + + curs_x = col; + curs_y = row; + + if (updating_screen == 0) + { + BLOCK_INPUT; + x_display_cursor (selected_screen, 1); + XFlushQueue (); + UNBLOCK_INPUT; + } +} + +/* Display a sequence of N glyphs found at GP. + WINDOW is the x-window to output to. LEFT and TOP are starting coords. + HL is 1 if this text is highlighted, 2 if the cursor is on it. + + FONT is the default font to use (for glyphs whose font-code is 0). */ + +static void +dumpglyphs (s, left, top, gp, n, hl, font) + struct screen *s; + int left, top; + register GLYPH *gp; /* Points to first GLYPH. */ + register int n; /* Number of glyphs to display. */ + int hl; + FONT_TYPE *font; +{ + char buf[s->width]; + register char *cp = buf; + register int len; + Window window = s->display.x->window_desc; + GC drawing_gc = (hl == 2 ? s->display.x->cursor_gc + : (hl ? s->display.x->reverse_gc + : s->display.x->normal_gc)); + + XDrawImageString16 (x_current_display, window, drawing_gc, + left, top + FONT_BASE (font), (XChar2b *) gp, n); +} + +#if 0 +static void +dumpglyphs (s, left, top, gp, n, hl, font) + struct screen *s; + int left, top; + register GLYPH *gp; /* Points to first GLYPH. */ + register int n; /* Number of glyphs to display. */ + int hl; + FONT_TYPE *font; +{ + char buf[s->width]; /* Holds characters to be displayed. */ + register char *cp; /* Steps through buf[]. */ + register int tlen = GLYPH_TABLE_LENGTH; + register Lisp_Object *tbase = GLYPH_TABLE_BASE; + Window window = s->display.x->window_desc; + int cursor_pixel = s->display.x->cursor_pixel; + int fg_pixel = s->display.x->foreground_pixel; + int bg_pixel = s->display.x->background_pixel; + int intborder = s->display.x->internal_border_width; + + while (n) + { + /* Get the face-code of the next GLYPH. */ + int cf, len; + int g = *gp; + + while (GLYPH_ALIAS_P (tbase, tlen, g)) + g = GLYPH_ALIAS (tbase, g); + + cf = g >> 8; + + /* Find the run of consecutive glyphs with the same face-code. + Extract their character codes into BUF. */ + cp = buf; + while (n > 0) + { + g = *gp; + while (GLYPH_ALIAS_P (tbase, tlen, g)) + g = GLYPH_ALIAS (tbase, g); + if ((g >> 8) != cf) + break; + + *cp++ = 0377 & g; + --n; + ++gp; + } + + /* LEN gets the length of the run. */ + len = cp - buf; + + /* Now output this run of chars, with the font and pixel values + determined by the face code CF. */ + if (cf == 0) + { +#ifdef HAVE_X11 + GC GC_cursor = s->display.x->cursor_gc; + GC GC_reverse = s->display.x->reverse_gc; + GC GC_normal = s->display.x->normal_gc; + + XDrawImageString (x_current_display, window, + (hl == 2 + ? GC_cursor + : (hl ? GC_reverse : GC_normal)), + left, top + FONT_BASE (font), buf, len); +#else + XText (window, left, top, + buf, + len, + font->id, + (hl == 2 + ? (cursor_pixel == fg_pixel ? bg_pixel : fg_pixel) + : hl ? bg_pixel : fg_pixel), + (hl == 2 ? cursor_pixel + : hl ? fg_pixel : bg_pixel)); +#endif /* HAVE_X11 */ + } + else + { +#ifdef HAVE_X11 + if (FACE_IS_FONT (cf)) + XDrawImageString (x_current_display, s->display.x->window_desc, + FACE_GC (cf), + left, top + FONT_BASE (FACE_FONT (cf)), + buf, len); + else if (FACE_IS_IMAGE (cf)) + XCopyPlane (x_current_display, FACE_IMAGE (cf), + s->display.x->window_desc, + s->display.x->normal_gc, + 0, 0, + FACE_IMAGE_WIDTH (cf), + FACE_IMAGE_HEIGHT (cf), left, top); + else + abort (); +#else + register struct face *fp = x_face_table[cf]; + + XText (window, left, top, + buf, + len, + fp->font->id, + (hl == 2 + ? (cursor_pixel == fp->fg ? fp->bg : fp->fg) + : hl ? fp->bg : fp->fg), + (hl == 2 ? cursor_pixel + : hl ? fp->fg : fp->bg)); +#endif /* HAVE_X11 */ + } + left += len * FONT_WIDTH (font); + } +} +#endif + +/* Output some text at the nominal screen cursor position, + advancing the cursor over the text. + Output LEN glyphs at START. + + `highlight', set up by XTreassert_line_highlight or XTchange_line_highlight, + controls the pixel values used for foreground and background. */ + +static +XTwrite_glyphs (start, len) + register GLYPH *start; + int len; +{ + register int temp_length; + int mask; + struct screen *s; + + BLOCK_INPUT; + + s = updating_screen; + if (s == 0) + { + s = selected_screen; + /* If not within an update, + output at the screen's visible cursor. */ + curs_x = s->cursor_x; + curs_y = s->cursor_y; + } + + /* Clear the cursor if it appears on this line. */ + if (curs_y == s->cursor_y) + x_display_cursor (s, 0); + + dumpglyphs (s, + (curs_x * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width), + (curs_y * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width), + start, len, highlight, s->display.x->font); + + if (updating_screen == 0) + { + s->cursor_x += len; + x_display_cursor (s, 1); + s->cursor_x -= len; + } + else + curs_x += len; + + UNBLOCK_INPUT; +} + +/* Erase the current text line from the nominal cursor position (inclusive) + to column FIRST_UNUSED (exclusive). The idea is that everything + from FIRST_UNUSED onward is already erased. */ + +static +XTclear_end_of_line (first_unused) + register int first_unused; +{ + struct screen *s = updating_screen; + int mask; + + if (s == 0) + abort (); + + if (curs_y < 0 || curs_y >= s->height) + return; + if (first_unused <= 0) + return; + + if (first_unused >= s->width) + first_unused = s->width; + + BLOCK_INPUT; + + /* Clear the cursor if it appears on this line. */ + if (curs_y == s->cursor_y) + x_display_cursor (s, 0); + +#ifdef HAVE_X11 + XClearArea (x_current_display, s->display.x->window_desc, + curs_x * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width, + curs_y * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width, + FONT_WIDTH (s->display.x->font) * (first_unused - curs_x), + FONT_HEIGHT (s->display.x->font), False); + +#else + XPixSet (s->display.x->window_desc, + curs_x * FONT_WIDTH (s->display.x->font) + s->display.x->internal_border_width, + curs_y * FONT_HEIGHT (s->display.x->font) + s->display.x->internal_border_width, + FONT_WIDTH (s->display.x->font) * (first_unused - curs_x), + FONT_HEIGHT (s->display.x->font), + s->display.x->background_pixel); +#endif /* HAVE_X11 */ + + UNBLOCK_INPUT; +} + +static +XTclear_screen () +{ + int mask; + struct screen *s = updating_screen; + + if (s == 0) + s = selected_screen; + + s->phys_cursor_x = -1; /* Cursor not visible. */ + curs_x = 0; /* Nominal cursor position is top left. */ + curs_y = 0; + + BLOCK_INPUT; + XClear (s->display.x->window_desc); +#ifndef HAVE_X11 + dumpborder (s, 0); +#endif + XFlushQueue (); + UNBLOCK_INPUT; +} + +/* Paint horzontal bars down the screen for a visible bell. + Note that this may be way too slow on some machines. */ + +XTflash (s) + struct screen *s; +{ + register struct screen_glyphs *active_screen = SCREEN_CURRENT_GLYPHS (s); + register int i; + int x, y; + + if (updating_screen != 0) + abort (); + + BLOCK_INPUT; +#ifdef HAVE_X11 +#if 0 + for (i = s->height * FONT_HEIGHT (s->display.x->font) - 10; + i >= 0; + i -= 100) /* Should be NO LOWER than 75 for speed reasons. */ + XFillRectangle (x_current_display, s->display.x->window_desc, + s->display.x->cursor_gc, + 0, i, s->width * FONT_WIDTH (s->display.x->font) + + 2 * s->display.x->internal_border_width, 25); +#endif + + x = (s->width * FONT_WIDTH (s->display.x->font)) / 4; + y = (s->height * FONT_HEIGHT (s->display.x->font)) / 4; + XFillRectangle (x_current_display, s->display.x->window_desc, + s->display.x->cursor_gc, + x, y, 2 * x, 2 * y); + dumpglyphs (s, (x + s->display.x->internal_border_width), + (y + s->display.x->internal_border_width), + &active_screen->glyphs[(s->height / 4) + 1][(s->width / 4)], + 1, 0, s->display.x->font); + +#else /* X10 */ + for (i = s->height * FONT_HEIGHT (s->display.x->font) - 10; + i >= 0; + i -= 50) + XPixFill (s->display.x->window_desc, 0, i, + s->width * FONT_WIDTH (s->display.x->font) + + 2 * s->display.x->internal_border_width, 10, + WHITE_PIX_DEFAULT, ClipModeClipped, GXinvert, AllPlanes); +#endif /* X10 */ + + XFlushQueue (); + UNBLOCK_INPUT; +} + +/* Flip background and forground colors of the screen. */ + +x_invert_screen (s) + struct screen *s; +{ +#ifdef HAVE_X11 + GC temp; + unsigned long pix_temp; + + x_display_cursor (s, 0); + XClearWindow (x_current_display, s->display.x->window_desc); + temp = s->display.x->normal_gc; + s->display.x->normal_gc = s->display.x->reverse_gc; + s->display.x->reverse_gc = temp; + pix_temp = s->display.x->foreground_pixel; + s->display.x->foreground_pixel = s->display.x->background_pixel; + s->display.x->background_pixel = pix_temp; + + XSetWindowBackground (x_current_display, s->display.x->window_desc, + s->display.x->background_pixel); + if (s->display.x->background_pixel == s->display.x->cursor_pixel) + { + s->display.x->cursor_pixel = s->display.x->foreground_pixel; + XSetBackground (x_current_display, s->display.x->cursor_gc, + s->display.x->cursor_pixel); + XSetForeground (x_current_display, s->display.x->cursor_gc, + s->display.x->background_pixel); + } + redraw_screen (s); +#endif /* X11 */ +} + +/* Make audible bell. */ + +#ifdef HAVE_X11 +#define XRINGBELL XBell(x_current_display, 0) +#else +#define XRINGBELL XFeep(0); +#endif + +XTring_bell () +{ + if (visible_bell) +#if 0 + XTflash (selected_screen); +#endif + { + x_invert_screen (selected_screen); + x_invert_screen (selected_screen); + } + else + { + BLOCK_INPUT; + XRINGBELL; + XFlushQueue (); + UNBLOCK_INPUT; + } +} + +/* Insert and delete character are not supposed to be used + because we are supposed to turn off the feature of using them. */ + +static +XTinsert_glyphs (start, len) + register char *start; + register int len; +{ + abort (); +} + +static +XTdelete_glyphs (n) + register int n; +{ + abort (); +} + +/* Specify how many text lines, from the top of the window, + should be affected by insert-lines and delete-lines operations. + This, and those operations, are used only within an update + that is bounded by calls to XTupdate_begin and XTupdate_end. */ + +static +XTset_terminal_window (n) + register int n; +{ + if (updating_screen == 0) + abort (); + + if ((n <= 0) || (n > updating_screen->height)) + flexlines = updating_screen->height; + else + flexlines = n; +} + +/* Perform an insert-lines operation, inserting N lines + at a vertical position curs_y. */ + +static void +stufflines (n) + register int n; +{ + register int topregion, bottomregion; + register int length, newtop, mask; + register struct screen *s = updating_screen; + int intborder = s->display.x->internal_border_width; + + if (curs_y >= flexlines) + return; + + topregion = curs_y; + bottomregion = flexlines - (n + 1); + newtop = topregion + n; + length = (bottomregion - topregion) + 1; + +#ifndef HAVE_X11 + dumpqueue (); +#endif + + if ((length > 0) && (newtop <= flexlines)) + { +#ifdef HAVE_X11 + XCopyArea (x_current_display, s->display.x->window_desc, + s->display.x->window_desc, s->display.x->normal_gc, + intborder, topregion * FONT_HEIGHT (s->display.x->font) + intborder, + s->width * FONT_WIDTH (s->display.x->font), + length * FONT_HEIGHT (s->display.x->font), intborder, + newtop * FONT_HEIGHT (s->display.x->font) + intborder); +#else + XMoveArea (s->display.x->window_desc, + intborder, topregion * FONT_HEIGHT (s->display.x->font) + intborder, + intborder, newtop * FONT_HEIGHT (s->display.x->font) + intborder, + s->width * FONT_WIDTH (s->display.x->font), + length * FONT_HEIGHT (s->display.x->font)); + /* Now we must process any ExposeRegion events that occur + if the area being copied from is obscured. + We can't let it wait because further i/d operations + may want to copy this area to another area. */ + x_read_exposes (); +#endif /* HAVE_X11 */ + } + + newtop = min (newtop, (flexlines - 1)); + length = newtop - topregion; + if (length > 0) + { +#ifdef HAVE_X11 + XClearArea (x_current_display, s->display.x->window_desc, intborder, + topregion * FONT_HEIGHT (s->display.x->font) + intborder, + s->width * FONT_WIDTH (s->display.x->font), + n * FONT_HEIGHT (s->display.x->font), False); +#else + XPixSet (s->display.x->window_desc, + intborder, + topregion * FONT_HEIGHT (s->display.x->font) + intborder, + s->width * FONT_WIDTH (s->display.x->font), + n * FONT_HEIGHT (s->display.x->font), + s->display.x->background_pixel); +#endif /* HAVE_X11 */ + } +} + +/* Perform a delete-lines operation, deleting N lines + at a vertical position curs_y. */ + +static void +scraplines (n) + register int n; +{ + int mask; + register struct screen *s = updating_screen; + int intborder = s->display.x->internal_border_width; + + if (curs_y >= flexlines) + return; + +#ifndef HAVE_X11 + dumpqueue (); +#endif + + if ((curs_y + n) >= flexlines) + { + if (flexlines >= (curs_y + 1)) + { +#ifdef HAVE_X11 + XClearArea (x_current_display, s->display.x->window_desc, intborder, + curs_y * FONT_HEIGHT (s->display.x->font) + intborder, + s->width * FONT_WIDTH (s->display.x->font), + (flexlines - curs_y) * FONT_HEIGHT (s->display.x->font), False); +#else + XPixSet (s->display.x->window_desc, + intborder, curs_y * FONT_HEIGHT (s->display.x->font) + intborder, + s->width * FONT_WIDTH (s->display.x->font), + (flexlines - curs_y) * FONT_HEIGHT (s->display.x->font), + s->display.x->background_pixel); +#endif /* HAVE_X11 */ + } + } + else + { +#ifdef HAVE_X11 + XCopyArea (x_current_display, s->display.x->window_desc, + s->display.x->window_desc, s->display.x->normal_gc, + intborder, + (curs_y + n) * FONT_HEIGHT (s->display.x->font) + intborder, + s->width * FONT_WIDTH (s->display.x->font), + (flexlines - (curs_y + n)) * FONT_HEIGHT (s->display.x->font), + intborder, curs_y * FONT_HEIGHT (s->display.x->font) + intborder); + XClearArea (x_current_display, s->display.x->window_desc, + intborder, + (flexlines - n) * FONT_HEIGHT (s->display.x->font) + intborder, + s->width * FONT_WIDTH (s->display.x->font), + n * FONT_HEIGHT (s->display.x->font), False); +#else + XMoveArea (s->display.x->window_desc, + intborder, + (curs_y + n) * FONT_HEIGHT (s->display.x->font) + intborder, + intborder, curs_y * FONT_HEIGHT (s->display.x->font) + intborder, + s->width * FONT_WIDTH (s->display.x->font), + (flexlines - (curs_y + n)) * FONT_HEIGHT (s->display.x->font)); + /* Now we must process any ExposeRegion events that occur + if the area being copied from is obscured. + We can't let it wait because further i/d operations + may want to copy this area to another area. */ + x_read_exposes (); + XPixSet (s->display.x->window_desc, intborder, + (flexlines - n) * FONT_HEIGHT (s->display.x->font) + intborder, + s->width * FONT_WIDTH (s->display.x->font), + n * FONT_HEIGHT (s->display.x->font), s->display.x->background_pixel); +#endif /* HAVE_X11 */ + } +} + +/* Perform an insert-lines or delete-lines operation, + inserting N lines or deleting -N lines at vertical position VPOS. */ + +XTins_del_lines (vpos, n) + int vpos, n; +{ + if (updating_screen == 0) + abort (); + + /* Clear the cursor. */ + x_display_cursor (updating_screen, 0); + + XTcursor_to (vpos, 0); + + BLOCK_INPUT; + if (n >= 0) + stufflines (n); + else + scraplines (-n); + XFlushQueue (); + UNBLOCK_INPUT; +} + +static void clear_cursor (); + +/* Output into a rectangle of an X-window (for screen S) + the characters in s->phys_lines that overlap that rectangle. + TOP and LEFT are the position of the upper left corner of the rectangle. + ROWS and COLS are the size of the rectangle. */ + +static void +dumprectangle (s, left, top, cols, rows) + struct screen *s; + register int left, top, cols, rows; +{ + register struct screen_glyphs *active_screen = SCREEN_CURRENT_GLYPHS (s); + int cursor_cleared = 0; + int bottom, right; + register int y; + + if (SCREEN_GARBAGED_P (s)) + return; + + top -= s->display.x->internal_border_width; + left -= s->display.x->internal_border_width; + + /* Express rectangle as four edges, instead of position-and-size. */ + bottom = top + rows; + right = left + cols; + +#ifndef HAVE_X11 /* Window manger does this for X11. */ + /* If the rectangle includes any of the internal border area, + redisplay the border emphasis. */ + if (top < 0 || left < 0 + || bottom > s->height * FONT_HEIGHT (s->display.x->font) + || right > s->width * FONT_WIDTH (s->display.x->font)) + dumpborder (s, 0); +#endif /* HAVE_X11 */ + + /* Convert rectangle edges in pixels to edges in chars. + Round down for left and top, up for right and bottom. */ + top /= FONT_HEIGHT (s->display.x->font); + left /= FONT_WIDTH (s->display.x->font); + bottom += (FONT_HEIGHT (s->display.x->font) - 1); + right += (FONT_WIDTH (s->display.x->font) - 1); + bottom /= FONT_HEIGHT (s->display.x->font); + right /= FONT_WIDTH (s->display.x->font); + + /* Clip the rectangle to what can be visible. */ + if (left < 0) + left = 0; + if (top < 0) + top = 0; + if (right > s->width) + right = s->width; + if (bottom > s->height) + bottom = s->height; + + /* Get size in chars of the rectangle. */ + cols = right - left; + rows = bottom - top; + + /* If rectangle has zero area, return. */ + if (rows <= 0) return; + if (cols <= 0) return; + + /* Turn off the cursor if it is in the rectangle. + We will turn it back on afterward. */ + if ((s->phys_cursor_x >= left) && (s->phys_cursor_x < right) + && (s->phys_cursor_y >= top) && (s->phys_cursor_y < bottom)) + { + clear_cursor (s); + cursor_cleared = 1; + } + + /* Display the text in the rectangle, one text line at a time. */ + + for (y = top; y < bottom; y++) + { + GLYPH *line = &active_screen->glyphs[y][left]; + + if (! active_screen->enable[y] || left > active_screen->used[y]) + continue; + + dumpglyphs (s, + (left * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width), + (y * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width), + line, min (cols, active_screen->used[y] - left), + active_screen->highlight[y], s->display.x->font); + } + + /* Turn the cursor on if we turned it off. */ + + if (cursor_cleared) + x_display_cursor (s, 1); + XFlushQueue (); +} + +#ifndef HAVE_X11 +/* Process all queued ExposeRegion events. */ + +static void +dumpqueue () +{ + register int i; + XExposeRegionEvent r; + + while (dequeue_event (&r, &x_expose_queue)) + { + struct screen *s = x_window_to_screen (r.window); + if (s->display.x->icon_desc == r.window) + refreshicon (s); + else + dumprectangle (s, r.x, r.y, r.width, r.height); + } + XFlushQueue (); +} +#endif + +/* Process all expose events that are pending. + Redraws the cursor if necessary on any screen that + is not in the process of being updated with update_screen. */ + +static void +x_do_pending_expose () +{ + int mask; + struct screen *s; + Lisp_Object tail, screen; + + if (expose_all_windows) + { + expose_all_windows = 0; + for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr) + { + register int temp_width, temp_height; + int intborder; + + screen = XCONS (tail)->car; + if (XTYPE (screen) != Lisp_Screen) + continue; + s = XSCREEN (screen); + if (s->output_method != output_x_window) + continue; + if (!s->visible) + continue; + if (!s->display.x->needs_exposure) + continue; + + intborder = s->display.x->internal_border_width; + + clear_cursor (s); + XGetWindowInfo (s->display.x->window_desc, &windowinfo); + temp_width = ((windowinfo.width - 2 * intborder + - s->display.x->v_scrollbar_width) + / FONT_WIDTH (s->display.x->font)); + temp_height = ((windowinfo.height- 2 * intborder + - s->display.x->h_scrollbar_height) + / FONT_HEIGHT (s->display.x->font)); + if (temp_width != s->width || temp_height != s->height) + { + change_screen_size (s, max (1, temp_height), + max (1, temp_width), 0); + x_resize_scrollbars (s); + } + s->display.x->left_pos = windowinfo.x; + s->display.x->top_pos = windowinfo.y; + dumprectangle (s, 0, 0, PIXEL_WIDTH (s), PIXEL_HEIGHT (s)); +#if 0 + dumpborder (s, 0); +#endif + s->display.x->needs_exposure = 0; + if (updating_screen != s) + x_display_cursor (s, 1); + XFlushQueue (); + } + } + else + /* Handle any individual-rectangle expose events queued + for various windows. */ +#ifdef HAVE_X11 + ; +#else + dumpqueue (); +#endif +} + +#ifdef HAVE_X11 +static void +screen_highlight (screen) + struct screen *screen; +{ + if (! EQ (Vx_no_window_manager, Qnil)) + XSetWindowBorder (x_current_display, screen->display.x->window_desc, + screen->display.x->border_pixel); + x_display_cursor (screen, 1); +} + +static void +screen_unhighlight (screen) + struct screen *screen; +{ + if (! EQ (Vx_no_window_manager, Qnil)) + XSetWindowBorderPixmap (x_current_display, screen->display.x->window_desc, + screen->display.x->border_tile); + x_display_cursor (screen, 1); +} +#else /* X10 */ +/* Dump the border-emphasis of screen S. + If S is selected, this is a lining of the same color as the border, + just within the border, occupying a portion of the internal border. + If S is not selected, it is background in the same place. + If ALWAYS is 0, don't bother explicitly drawing if it's background. + + ALWAYS = 1 is used when a screen becomes selected or deselected. + In that case, we also turn the cursor off and on again + so it will appear in the proper shape (solid if selected; else hollow.) */ + +static void +dumpborder (s, always) + struct screen *s; + int always; +{ + int thickness = s->display.x->internal_border_width / 2; + int width = PIXEL_WIDTH (s); + int height = PIXEL_HEIGHT (s); + int pixel; + + if (s != selected_screen) + { + if (!always) + return; + + pixel = s->display.x->background_pixel; + } + else + { + pixel = s->display.x->border_pixel; + } + + XPixSet (s->display.x->window_desc, 0, 0, width, thickness, pixel); + XPixSet (s->display.x->window_desc, 0, 0, thickness, height, pixel); + XPixSet (s->display.x->window_desc, 0, height - thickness, width, + thickness, pixel); + XPixSet (s->display.x->window_desc, width - thickness, 0, thickness, + height, pixel); + + if (always) + x_display_cursor (s, 1); +} +#endif /* X10 */ + +/* The focus has changed. Update the screens as necessary to reflect + the new situation. Note that we can't change the selected screen + here, because the lisp code we are interrupting might become confused. + For that, we enqueue a screen_selected event. + + Return the number of events stored at bufp. */ +static int +x_new_focus_screen (screen, bufp, buf_free) + struct screen *screen; + struct input_event *bufp; + int buf_free; +{ + struct screen *old_focus = x_focus_screen; + int events_enqueued = 0; + + if (screen == x_focus_screen) + return 0; + + /* Set this before calling screen_{un,}highlight, so that they see + the correct value of x_focus_screen. */ + x_focus_screen = screen; + + if (old_focus) + { + if (old_focus->auto_lower) + x_lower_screen (old_focus); + screen_unhighlight (old_focus); + } + +#if 0 + selected_screen = screen; + XSET (XWINDOW (selected_screen->selected_window)->screen, + Lisp_Screen, selected_screen); + Fselect_window (selected_screen->selected_window); + choose_minibuf_screen (); +#endif + + if (x_focus_screen) + { + if (x_focus_screen->auto_raise) + x_raise_screen (x_focus_screen); + screen_highlight (x_focus_screen); + + /* Enqueue an event. It's kind of important not to drop these + events, but the event queue's fixed size is a real pain in the butt + anyway. */ + if (buf_free > 0) + { + bufp->kind = screen_selected; + bufp->screen = screen; + events_enqueued++; + } + } + + return events_enqueued; +} + +enum window_type +{ + no_window, + scrollbar_window, + text_window, +}; + +/* Symbol returned in input stream to indicate mouse movement. */ +Lisp_Object Qmouse_moved; + +/* Position of the mouse in characters */ +unsigned int x_mouse_x, x_mouse_y; + +/* Emacs window the mouse is in, if any. */ +extern Lisp_Object Vmouse_window; + +/* Offset in buffer of character under the pointer, or 0. */ +extern int mouse_buffer_offset; + +/* Part of the screen the mouse is in. */ +extern Lisp_Object Vmouse_screen_part; + +extern void pixel_to_glyph_translation (); +extern int buffer_posn_from_coords (); + +/* Symbols from xfns.c to denote the different parts of a window. */ +extern Lisp_Object Qmodeline_part, Qtext_part; + +#if 0 +/* Set *RESULT to an emacs input_event corresponding to MOTION_EVENT. + S is the screen in which the event occurred. + + WINDOW_TYPE says whether the event happened in a scrollbar window + or a text window, affecting the format of the event created. + + PART specifies which part of the scrollbar the event happened in, + if WINDOW_TYPE == scrollbar_window. + + If the mouse is over the same character as the last time we checked, + don't return an event; set result->kind to no_event. */ + +static void +notice_mouse_movement (result, motion_event, s, window_type, part) + struct input_event *result; + XMotionEvent motion_event; + struct screen *s; + int window_type; + Lisp_Object part; +{ + int x, y, root_x, root_y, pix_x, pix_y; + unsigned int keys_and_buttons; + Window w, root_window; + + /* Unless we decide otherwise below, return a non-event. */ + result->kind = no_event; + + if (XQueryPointer (x_current_display, + s->display.x->window_desc, + &root_window, &w, + &root_x, &root_y, &pix_x, &pix_y, + &keys_and_buttons) + == False) + return; + +#if 0 + if (w == None) /* Mouse no longer in window. */ + return Qnil; +#endif + + pixel_to_glyph_translation (s, pix_x, pix_y, &x, &y); + if (x == x_mouse_x && y == x_mouse_y) + return; + + x_mouse_x = x; + x_mouse_y = y; + + /* What sort of window are we in now? */ + if (window_type == text_window) /* Text part */ + { + int modeline_p; + + Vmouse_window = window_from_coordinates (s, x, y, &modeline_p); + + if (XTYPE (Vmouse_window) == Lisp_Window) + mouse_buffer_offset + = buffer_posn_from_coords (XWINDOW (Vmouse_window), x, y); + else + mouse_buffer_offset = 0; + + if (EQ (Vmouse_window, Qnil)) + Vmouse_screen_part = Qnil; + else if (modeline_p) + Vmouse_screen_part = Qmodeline_part; + else + Vmouse_screen_part = Qtext_part; + + result->kind = window_sys_event; + result->code = Qmouse_moved; + + return; + } + else if (window_type == scrollbar_window) /* Scrollbar */ + { + Vmouse_window = s->selected_window; + mouse_buffer_offset = 0; + Vmouse_screen_part = part; + + result->kind = window_sys_event; + result->code = Qmouse_moved; + + return; + } + + return; +} +#endif + +/* Given a pixel position (pix_x, pix_y) on the screen s, return + character co-ordinates in (*x, *y). */ +void +pixel_to_glyph_translation (s, pix_x, pix_y, x, y) + SCREEN_PTR s; + register unsigned int pix_x, pix_y; + register int *x, *y; +{ + register struct screen_glyphs *s_glyphs = SCREEN_CURRENT_GLYPHS (s); + register int line = SCREEN_HEIGHT (s) - 1; + int ibw = s->display.x->internal_border_width; + + /* What line is it on? */ + line = SCREEN_HEIGHT (s) - 1; + while (s_glyphs->top_left_y[line] > pix_y) + line--; + *y = line; + + /* Horizontally, is it in the border? */ + if (pix_x < ibw) + *x = 0; + + /* If it's off the right edge, clip it. */ + else if (pix_x > s->display.x->pixel_width - ibw) + *x = SCREEN_WIDTH (s) - 1; + + /* It's in the midst of the screen; assume all the characters are + the same width, and figure the column. */ + else + *x = (pix_x - ibw) / FONT_WIDTH (s->display.x->font); +} + +#ifdef HAVE_X11 + +/* Any buttons grabbed. */ +unsigned int x_mouse_grabbed; + +/* Convert a set of X modifier bits to the proper form for a + struct input_event modifiers value. */ + +static Lisp_Object +x_convert_modifiers (state) + unsigned int state; +{ + return ( ((state & (ShiftMask | LockMask)) ? shift_modifier : 0) + | ((state & ControlMask) ? ctrl_modifier : 0) + | ((state & Mod1Mask) ? meta_modifier : 0)); +} + +extern struct screen *x_window_to_scrollbar (); +extern Lisp_Object Vmouse_event; + +/* Prepare a mouse-event in *RESULT for placement in the input queue. + + If the event is a button press, then note that we have grabbed + the mouse. + + If PART and PREFIX are 0, then the event occurred in the text part; + otherwise it happened in a scrollbar. */ + +static Lisp_Object +construct_mouse_click (result, event, s, part, prefix) + struct input_event *result; + XButtonEvent *event; + struct screen *s; + int prefix; + Lisp_Object part; +{ + /* Initialize those fields text and scrollbar clicks hold in common. + Make the event type no_event; we'll change that when we decide + otherwise. */ + result->kind = no_event; + XSET (result->code, Lisp_Int, event->button); + result->modifiers = (x_convert_modifiers (event->state) + | (event->type == ButtonRelease ? up_modifier : 0)); + XSET (result->timestamp, Lisp_Int, (event->time & 0x7fffff)); + + /* Notice if the mouse is still grabbed. */ + if (event->type == ButtonPress) + { + if (! x_mouse_grabbed) + Vmouse_depressed = Qt; + x_mouse_grabbed |= event->button; + } + else if (event->type == ButtonRelease) + { + x_mouse_grabbed &= ~(event->button); + if (!x_mouse_grabbed) + Vmouse_depressed = Qnil; + } + + if (part) /* Scrollbar event */ + { + int pos, len; + + pos = event->y - (s->display.x->v_scrollbar_width - 2); + XSET (x_mouse_x, Lisp_Int, pos); + len = ((FONT_HEIGHT (s->display.x->font) * s->height) + + s->display.x->internal_border_width + - (2 * (s->display.x->v_scrollbar_width - 2))); + XSET (x_mouse_y, Lisp_Int, len); + + result->kind = scrollbar_click; + result->part = part; + XSET (result->x, Lisp_Int, (s->display.x->top_pos - event->y)); + XSET (result->y, Lisp_Int, s->display.x->pixel_height); + result->screen = s; + } + else /* Text Window Event */ + { + int row, column; + + pixel_to_glyph_translation (s, + event->x, event->y, + &column, &row); + + result->kind = mouse_click; + result->x = column; + result->y = row; + result->screen = s; + } +} + + +static char *events[] = +{ + "0: ERROR!", + "1: REPLY", + "KeyPress", + "KeyRelease", + "ButtonPress", + "ButtonRelease", + "MotionNotify", + "EnterNotify", + "LeaveNotify", + "FocusIn", + "FocusOut", + "KeymapNotify", + "Expose", + "GraphicsExpose", + "NoExpose", + "VisibilityNotify", + "CreateNotify", + "DestroyNotify", + "UnmapNotify", + "MapNotify", + "MapRequest", + "ReparentNotify", + "ConfigureNotify", + "ConfigureRequest", + "GravityNotify", + "ResizeRequest", + "CirculateNotify", + "CirculateRequest", + "PropertyNotify", + "SelectionClear", + "SelectionRequest", + "SelectionNotify", + "ColormapNotify", + "ClientMessage", + "MappingNotify", + "LASTEvent" +}; +#else /* X10 */ +#define XEvent XKeyPressedEvent +#endif /* HAVE_X11 */ + +/* Symbols returned in the input stream to indicate various X events. */ +Lisp_Object Qmapped_screen; +Lisp_Object Qunmapped_screen; +Lisp_Object Qexited_scrollbar; +Lisp_Object Qexited_window; +Lisp_Object Qredraw_screen; +Lisp_Object Qmouse_click; +Lisp_Object Qscrollbar_click; + +/* Timestamp of enter window event. This is only used by XTread_socket, + but we have to put it out here, since static variables within functions + sometimes don't work. */ +static Time enter_timestamp; + +/* Read events coming from the X server. + This routine is called by the SIGIO handler. + We return as soon as there are no more events to be read. + + Events representing keys are stored in buffer BUFP, + which can hold up to NUMCHARS characters. + We return the number of characters stored into the buffer, + thus pretending to be `read'. + + WAITP is nonzero if we should block until input arrives. + EXPECTED is nonzero if the caller knows input is available. */ + +Lisp_Object +XTread_socket (sd, bufp, numchars, waitp, expected) + register int sd; + register struct input_event *bufp; + register int numchars; + int waitp; + int expected; +{ + int count = 0; + int nbytes = 0; + int mask; + int items_pending; /* How many items are in the X queue. */ + XEvent event; + struct screen *s; + int event_found; + int prefix; + Lisp_Object part; + + if (x_input_blocked) + { + x_pending_input = 1; + return -1; + } + + x_pending_input = 0; + BLOCK_INPUT; + + if (numchars <= 0) + abort (); /* Don't think this happens. */ + +#ifdef FIOSNBIO + /* If available, Xlib uses FIOSNBIO to make the socket + non-blocking, and then looks for EWOULDBLOCK. If O_NDELAY is set, + FIOSNBIO is ignored, and instead of signalling EWOULDBLOCK, + a read returns 0, which Xlib interprets as equivalent to EPIPE. */ + fcntl (fileno (stdin), F_SETFL, 0); +#endif + +#ifndef SIGIO +#ifndef HAVE_SELECT + if (! (fcntl (fileno (stdin), F_GETFL, 0) & O_NDELAY)) + { + extern int read_alarm_should_throw; + read_alarm_should_throw = 1; + XPeekEvent (XDISPLAY &event); + read_alarm_should_throw = 0; + } +#endif +#endif + + while (XStuffPending () != 0) + { + XNextEvent (XDISPLAY &event); + event_found = 1; + + switch (event.type) + { +#ifdef HAVE_X11 + + case SelectionClear: /* Someone has grabbed ownership. */ + x_disown_selection (event.xselectionclear.window, + event.xselectionclear.selection, + event.xselectionclear.time); + break; + + case SelectionRequest: /* Someone wants our selection. */ + x_answer_selection_request (event); + break; + + case PropertyNotify: + /* If we were to do this synchronously, there'd be no worry + about re-selecting. */ + x_send_incremental (event); + break; + + case Expose: + s = x_window_to_screen (event.xexpose.window); + if (s) + { + if (s->visible == 0) + { + s->visible = 1; + s->iconified = 0; + SET_SCREEN_GARBAGED (s); + } + else + dumprectangle (x_window_to_screen (event.xexpose.window), + event.xexpose.x, event.xexpose.y, + event.xexpose.width, event.xexpose.height); + } + break; + + case GraphicsExpose: /* This occurs when an XCopyArea's + source area was obscured or not + available.*/ + dumprectangle (x_window_to_screen (event.xgraphicsexpose.drawable), + event.xgraphicsexpose.x, event.xgraphicsexpose.y, + event.xgraphicsexpose.width, + event.xgraphicsexpose.height); + break; + + case NoExpose: /* This occurs when an XCopyArea's + source area was completely + available */ + break; +#else /* not HAVE_X11 */ + case ExposeWindow: + if (event.subwindow != 0) + break; /* duplicate event */ + s = x_window_to_screen (event.window); + if (event.window == s->display.x->icon_desc) + { + refreshicon (s); + s->iconified = 1; + } + if (event.window == s->display.x->window_desc) + { + /* Say must check all windows' needs_exposure flags. */ + expose_all_windows = 1; + s->display.x->needs_exposure = 1; + s->visible = 1; + } + break; + + case ExposeRegion: + if (event.subwindow != 0) + break; /* duplicate event */ + s = x_window_to_screen (event.window); + if (event.window == s->display.x->icon_desc) + { + refreshicon (s); + break; + } + /* If window already needs full redraw, ignore this rectangle. */ + if (expose_all_windows && s->display.x->needs_exposure) + break; + /* Put the event on the queue of rectangles to redraw. */ + if (enqueue_event (&event, &x_expose_queue)) + /* If it is full, we can't record the rectangle, + so redraw this entire window. */ + { + /* Say must check all windows' needs_exposure flags. */ + expose_all_windows = 1; + s->display.x->needs_exposure = 1; + } + break; + + case ExposeCopy: + /* This should happen only when we are expecting it, + in x_read_exposes. */ + abort (); +#endif /* not HAVE_X11 */ + +#ifdef HAVE_X11 + case UnmapNotify: + { + XWMHints *hints; + + s = x_window_to_screen (event.xunmap.window); + if (s) /* S may no longer exist if + the screen was deleted. */ + { + /* While a screen is unmapped, display generation is + disabled; you don't want to spend time updating a + display that won't ever be seen. */ + s->visible = 0; + Vmouse_window = Vmouse_screen_part = Qnil; + x_mouse_x = x_mouse_y = -1; + } + } + break; + + case MapNotify: + s = x_window_to_screen (event.xmap.window); + if (s) + { + s->visible = 1; + s->iconified = 0; + + /* wait_reading_process_input will notice this and update + the screen's display structures. */ + SET_SCREEN_GARBAGED (s); + } + break; + + /* Turn off processing if we become fully obscured. */ + case VisibilityNotify: + break; + +#else + case UnmapWindow: + s = x_window_to_screen (event.window); + if (event.window == s->display.x->icon_desc) + s->iconified = 0; + if (event.window == s->display.x->window_desc) + s->visible = 0; + break; +#endif /* HAVE_X11 */ + +#ifdef HAVE_X11 + case KeyPress: + s = x_window_to_screen (event.xkey.window); + if (s != 0) + { + KeySym keysym; + XComposeStatus status; + char copy_buffer[80]; + + /* This will have to go some day... */ + nbytes = XLookupString (&event.xkey, + copy_buffer, + 80, + &keysym, + &status); + + if (numchars > 1) + { + if (IsCursorKey (keysym) /* >= 0xff50 < 0xff60 */ + || IsMiscFunctionKey (keysym) /* >= 0xff60 < 0xff80 */ + || IsKeypadKey (keysym) /* >= 0xff80 <= 0xffbd */ + || IsFunctionKey (keysym)) /* >= 0xffbe <= 0xffe0 */ + { + bufp->kind = non_ascii_keystroke; + bufp->code = (unsigned) keysym - 0xff50; + bufp->modifiers = x_convert_modifiers (event.xkey.state); + bufp++; + count++; + numchars--; + } + else if (numchars > nbytes) + { + register int i; + + if (nbytes == 1) + { + if (event.xkey.state & Mod1Mask) + *copy_buffer |= METABIT; + bufp->kind = ascii_keystroke; + XSET (bufp->code, Lisp_Int, *copy_buffer); + bufp++; + } + else + for (i = nbytes - 1; i > 1; i--) + { + bufp->kind = ascii_keystroke; + XSET (bufp->code, Lisp_Int, copy_buffer[i]); + bufp++; + } + + count += nbytes; + numchars -= nbytes; + } + } + } + break; +#else + case KeyPressed: + { + register char *where_mapping; + + s = x_window_to_screen (event.window); + /* Ignore keys typed on icon windows. */ + if (s != 0 && event.window == s->display.x->icon_desc) + break; + where_mapping = XLookupMapping (&event, &nbytes); + /* Nasty fix for arrow keys */ + if (!nbytes && IsCursorKey (event.detail & 0xff)) + { + switch (event.detail & 0xff) + { + case KC_CURSOR_LEFT: + where_mapping = "\002"; + break; + case KC_CURSOR_RIGHT: + where_mapping = "\006"; + break; + case KC_CURSOR_UP: + where_mapping = "\020"; + break; + case KC_CURSOR_DOWN: + where_mapping = "\016"; + break; + } + nbytes = 1; + } + if (numchars - nbytes > 0) + { + register int i; + + for (i = 0; i < nbytes; i++) + { + bufp->kind = ascii_keystroke; + XSET (bufp->code, Lisp_Int, where_mapping[i]); + bufp++; + } + count += nbytes; + numchars -= nbytes; + } + } + break; +#endif /* HAVE_X11 */ + +#ifdef HAVE_X11 + case EnterNotify: + if (event.xcrossing.detail == NotifyInferior) /* Left Scrollbar */ + ; + else if (event.xcrossing.focus) /* Entered Window */ + { + /* If we decide we want to generate an event to be seen + by the rest of Emacs, we put it here. */ + struct input_event emacs_event; + emacs_event.kind = no_event; + + s = x_window_to_screen (event.xcrossing.window); + + /* Avoid nasty pop/raise loops. */ + if (s && (!(s->auto_raise) + || !(s->auto_lower) + || (event.xcrossing.time - enter_timestamp) > 500)) + { + int n = x_new_focus_screen (s, bufp, numchars); + bufp += n; + numchars -= n; + enter_timestamp = event.xcrossing.time; + } +#if 0 + else if ((s = x_window_to_scrollbar (event.xcrossing.window, + &part, &prefix))) + /* Fake a motion event */ + notice_mouse_movement (&emacs_event, + event.xmotion, s, scrollbar_window, + part); +#endif + +#if 0 + if (! EQ (Vx_send_mouse_movement_events, Qnil) + && numchars >= 1 + && emacs_event.kind != no_event) + { + bcopy (&emacs_event, bufp, sizeof (struct input_event)); + bufp++; + count++; + numchars--; + } +#endif + } +#if 0 + else if (s = x_window_to_screen (event.xcrossing.window)) + x_mouse_screen = s; +#endif + + break; + + case FocusIn: + s = x_window_to_screen (event.xfocus.window); + if (s) + { + int n = x_new_focus_screen (s, bufp, numchars); + bufp += n; + numchars -= n; + } + break; + + case LeaveNotify: + if (event.xcrossing.detail != NotifyInferior + && event.xcrossing.subwindow == None + && event.xcrossing.mode == NotifyNormal) + { + if (event.xcrossing.focus + && (x_focus_screen + == x_window_to_screen (event.xcrossing.window))) + { + int n = x_new_focus_screen (0, bufp, numchars); + bufp += n; + numchars -= n; + } + } + break; + + case FocusOut: + s = x_window_to_screen (event.xfocus.window); + if (s && s == x_focus_screen) + { + int n = x_new_focus_screen (0, bufp, numchars); + bufp += n; + numchars -= n; + } + break; + +#else /* not HAVE_X11 */ + + case EnterWindow: + if ((event.detail & 0xFF) == 1) + break; /* Coming from our own subwindow */ + if (event.subwindow != 0) + break; /* Entering our own subwindow. */ + + { + extern int waiting_for_input; + struct screen *old_s = x_input_screen; + + s = x_window_to_screen (event.window); + x_mouse_screen = s; + + if (waiting_for_input && x_focus_screen == 0) + x_new_selected_screen (s); + } + break; + + case LeaveWindow: + if ((event.detail & 0xFF) == 1) + break; /* Entering our own subwindow */ + if (event.subwindow != 0) + break; /* Leaving our own subwindow. */ + + x_mouse_screen = 0; + if (x_focus_screen == 0 + && x_input_screen != 0 + && x_input_screen == x_window_to_screen (event.window) + && event.window == x_input_screen->display.x->window_desc) + { + s = x_input_screen; + x_input_screen = 0; + if (s) + screen_unhighlight (s); + } + break; +#endif /* not HAVE_X11 */ + +#ifdef HAVE_X11 + case MotionNotify: + { + s = x_window_to_screen (event.xmotion.window); + if (s) + { + int row, column; + + pixel_to_glyph_translation (s, + event.xmotion.x, event.xmotion.y, + &column, &row); + + note_mouse_position (s, column, row, event.xmotion.time); + } +#if 0 + else if ((s = x_window_to_scrollbar (event.xmotion.window, + &part, &prefix))) + { + What should go here? + } +#endif + } + break; + + case ConfigureNotify: + { + int rows, columns; + s = x_window_to_screen (event.xconfigure.window); + if (!s) + break; + + columns = ((event.xconfigure.width - + (2 * s->display.x->internal_border_width) + - s->display.x->v_scrollbar_width) + / FONT_WIDTH (s->display.x->font)); + rows = ((event.xconfigure.height - + (2 * s->display.x->internal_border_width) + - s->display.x->h_scrollbar_height) + / FONT_HEIGHT (s->display.x->font)); + + if (columns != s->width || rows != s->height) + { + XEvent ignored_event; + + change_screen_size (s, rows, columns, 0); + x_resize_scrollbars (s); + SET_SCREEN_GARBAGED (s); +#if 0 + dumprectangle (s, 0, 0, PIXEL_WIDTH (s), PIXEL_HEIGHT (s)); + /* Throw away the exposures generated by this reconfigure. */ + while (XCheckWindowEvent (x_current_display, + event.xconfigure.window, + ExposureMask, &ignored_event) + == True); +#endif + } + + s->display.x->left_pos = event.xconfigure.x; + s->display.x->top_pos = event.xconfigure.y; + s->display.x->pixel_width = event.xconfigure.width; + s->display.x->pixel_height = event.xconfigure.height; + break; + } + + case ButtonPress: + case ButtonRelease: + { + /* If we decide we want to generate an event to be seen + by the rest of Emacs, we put it here. */ + struct input_event emacs_event; + emacs_event.kind = no_event; + + s = x_window_to_screen (event.xbutton.window); + if (s) + if (!x_focus_screen || (s == x_focus_screen)) + construct_mouse_click (&emacs_event, + &event, s, 0, 0); + else + continue; + else + if ((s = x_window_to_scrollbar (event.xbutton.window, + &part, &prefix))) + { + if (!x_focus_screen || (selected_screen == x_focus_screen)) + construct_mouse_click (&emacs_event, + &event, s, part, prefix); + else + continue; + } + + if (numchars >= 1 && emacs_event.kind != no_event) + { + bcopy (&emacs_event, bufp, sizeof (struct input_event)); + bufp++; + count++; + numchars--; + } + } + break; + +#else /* not HAVE_X11 */ + case ButtonPressed: + case ButtonReleased: + s = x_window_to_screen (event.window); + if (s) + { + if (event.window == s->display.x->icon_desc) + { + x_make_screen_visible (s); + + if (warp_mouse_on_deiconify) + XWarpMouse (s->display.x->window_desc, 10, 10); + break; + } + if (event.window == s->display.x->window_desc) + { + if (s->auto_raise) + x_raise_screen (s); + } + } + enqueue_event (&event, &x_mouse_queue); + if (numchars >= 2) + { + bufp->kind = ascii_keystroke; + bufp->code = (char) 'X' & 037; /* C-x */ + bufp++; + + bufp->kind = ascii_keystroke; + bufp->code = (char) 0; /* C-@ */ + bufp++; + + count += 2; + numchars -= 2; + } + break; +#endif /* not HAVE_X11 */ + +#ifdef HAVE_X11 + + case CirculateNotify: + break; + case CirculateRequest: + break; + +#endif /* HAVE_X11 */ + + case MappingNotify: + if (event.xmapping.request == MappingKeyboard) + /* Someone has changed the keyboard mapping - flush the + local cache. */ + XRefreshKeyboardMapping (&event.xmapping); + break; + + default: + break; + } + } + +#if 0 +#ifdef HAVE_SELECT + if (expected && ! event_found) + { + /* AOJ 880406: if select returns true but XPending doesn't, it means that + there is an EOF condition; in other words, that X has died. + Act as if there had been a hangup. */ + + int fd = ConnectionNumber (x_current_display); + int mask = 1 << fd; + + if (0 != select (fd + 1, &mask, (long *) 0, (long *) 0, + (struct timeval *) 0) + && !XStuffPending ()) + kill (getpid (), SIGHUP); + } +#endif /* HAVE_SELECT */ +#endif + + if (updating_screen == 0) + x_do_pending_expose (); + + UNBLOCK_INPUT; + return count; +} + +#ifndef HAVE_X11 +/* Read and process only Expose events + until we get an ExposeCopy event; then return. + This is used in insert/delete line. + We assume input is already blocked. */ + +static void +x_read_exposes () +{ + struct screen *s; + XKeyPressedEvent event; + + while (1) + { + /* while there are more events*/ + XMaskEvent (ExposeWindow | ExposeRegion | ExposeCopy, &event); + switch (event.type) + { + case ExposeWindow: + if (event.subwindow != 0) + break; /* duplicate event */ + s = x_window_to_screen (event.window); + if (event.window == s->display.x->icon_desc) + { + refreshicon (s); + break; + } + if (event.window == s->display.x->window_desc) + { + expose_all_windows = 1; + s->display.x->needs_exposure = 1; + break; + } + break; + + case ExposeRegion: + if (event.subwindow != 0) + break; /* duplicate event */ + s = x_window_to_screen (event.window); + if (event.window == s->display.x->icon_desc) + { + refreshicon (s); + break; + } + /* If window already needs full redraw, ignore this rectangle. */ + if (expose_all_windows && s->display.x->needs_exposure) + break; + /* Put the event on the queue of rectangles to redraw. */ + if (enqueue_event (&event, &x_expose_queue)) + /* If it is full, we can't record the rectangle, + so redraw this entire window. */ + { + /* Say must check all windows' needs_exposure flags. */ + expose_all_windows = 1; + s->display.x->needs_exposure = 1; + } + break; + + case ExposeCopy: + return; + } + } +} +#endif /* HAVE_X11 */ + +static int +XTmouse_tracking_enable (enable) + int enable; +{ + Lisp_Object tail; + + /* Go through the list of screens and turn on/off mouse tracking for + each of them. */ + for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr) + { + if (XTYPE (XCONS (tail)->car) != Lisp_Screen) + abort (); + if (XSCREEN (XCONS (tail)->car)->output_method == output_x_window) + XSelectInput (x_current_display, + XSCREEN (XCONS (tail)->car)->display.x->window_desc, + (enable + ? (STANDARD_EVENT_SET + | PointerMotionMask + | ButtonReleaseMask) + : STANDARD_EVENT_SET)); + } +} + + +static Lisp_Object +XTmouse_position () +{ + +} + + + +/* Draw a hollow box cursor. Don't change the inside of the box. */ + +static void +x_draw_box (s) + struct screen *s; +{ + int left = s->cursor_x * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width; + int top = s->cursor_y * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width; + int width = FONT_WIDTH (s->display.x->font); + int height = FONT_HEIGHT (s->display.x->font); + +#ifdef HAVE_X11 + /* Perhaps we should subtract 1 from width and height... */ + XDrawRectangle (x_current_display, s->display.x->window_desc, + s->display.x->cursor_gc, + left, top, width - 1, height - 1); +#else + XPixSet (s->display.x->window_desc, + left, top, width, 1, + s->display.x->cursor_pixel); + + XPixSet (s->display.x->window_desc, + left, top, 1, height, + s->display.x->cursor_pixel); + + XPixSet (s->display.x->window_desc, + left+width-1, top, 1, height, + s->display.x->cursor_pixel); + + XPixSet (s->display.x->window_desc, + left, top+height-1, width, 1, + s->display.x->cursor_pixel); +#endif /* HAVE_X11 */ +} + +/* Clear the cursor of screen S to background color, + and mark the cursor as not shown. + This is used when the text where the cursor is + is about to be rewritten. */ + +static void +clear_cursor (s) + struct screen *s; +{ + int mask; + + if (! s->visible + || s->phys_cursor_x < 0) + return; + +#ifdef HAVE_X11 + x_display_cursor (s, 0); +#if 0 + XClearArea (x_current_display, s->display.x->window_desc, + s->phys_cursor_x * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width, + s->phys_cursor_y * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width, + FONT_WIDTH (s->display.x->font) + 1, FONT_HEIGHT (s->display.x->font) + 1, False); +#endif +#else + XPixSet (s->display.x->window_desc, + s->phys_cursor_x * FONT_WIDTH (s->display.x->font) + s->display.x->internal_border_width, + s->phys_cursor_y * FONT_HEIGHT (s->display.x->font) + s->display.x->internal_border_width, + FONT_WIDTH (s->display.x->font), FONT_HEIGHT (s->display.x->font), + s->display.x->background_pixel); +#endif /* HAVE_X11 */ + s->phys_cursor_x = -1; +} + +x_display_bar_cursor (s, on) + struct screen *s; + int on; +{ + register int phys_x = s->phys_cursor_x; + register int phys_y = s->phys_cursor_y; + register int x1; + register int y1; + register int y2; + + if (! s->visible || (! on && s->phys_cursor_x < 0)) + return; + +#ifdef HAVE_X11 + if (phys_x >= 0 && + (!on || phys_x != s->cursor_x || phys_y != s->cursor_y)) + { + x1 = phys_x * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width; + y1 = phys_y * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width - 1; + y2 = y1 + FONT_HEIGHT (s->display.x->font) + 1; + + XDrawLine (x_current_display, s->display.x->window_desc, + s->display.x->reverse_gc, x1, y1, x1, y2); + + s->phys_cursor_x = phys_x = -1; + } + + if (on && s == x_focus_screen) + { + x1 = s->cursor_x * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width; + y1 = s->cursor_y * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width - 1; + y2 = y1 + FONT_HEIGHT (s->display.x->font) + 1; + + XDrawLine (x_current_display, s->display.x->window_desc, + s->display.x->cursor_gc, x1, y1, x1, y2); + + s->phys_cursor_x = s->cursor_x; + s->phys_cursor_y = s->cursor_y; + } +#else /* X10 */ + Give it up, dude. +#endif /* X10 */ +} + + +/* Redraw the glyph at ROW, COLUMN on screen S, in the style HIGHLIGHT. + If there is no character there, erase the area. HIGHLIGHT is as + defined for dumpglyphs. */ + +static void +x_draw_single_glyph (s, row, column, highlight) + struct screen *s; + int row, column; + int highlight; +{ + register struct screen_glyphs *current_screen = SCREEN_CURRENT_GLYPHS (s); + + /* If there is supposed to be a character there, redraw it + in that line's normal video. */ + if (current_screen->enable[row] + && column < current_screen->used[row]) + dumpglyphs (s, + (column * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width), + (row * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width), + ¤t_screen->glyphs[row][column], + 1, highlight, s->display.x->font); + else + { +#ifdef HAVE_X11 + static GLYPH a_space_glyph = SPACEGLYPH; + dumpglyphs (s, + (column * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width), + (row * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width), + &a_space_glyph, 1, highlight, s->display.x->font); +#else + XPixSet (s->display.x->window_desc, + (column * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width), + (row * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width), + FONT_WIDTH (s->display.x->font), + FONT_HEIGHT (s->display.x->font), + (highlight == 0 + ? s->display.x->background_pixel + : (highlight == 1 + ? s->display.x->foreground_pixel + : s->display.x->cursor_pixel))); +#endif /* HAVE_X11 */ + } +} + +/* Turn the displayed cursor of screen S on or off according to ON. + If ON is nonzero, where to put the cursor is specified + by S->cursor_x and S->cursor_y. */ + +static void +x_display_box_cursor (s, on) + struct screen *s; + int on; +{ + if (! s->visible) + return; + + /* If cursor is off and we want it off, return quickly. */ + + if (!on && s->phys_cursor_x < 0) + return; + + /* If cursor is currently being shown and we don't want it to be + or it is in the wrong place, + or we want a hollow box and it's not so, (pout!) + erase it. */ + if (s->phys_cursor_x >= 0 + && (!on + || s->phys_cursor_x != s->cursor_x + || s->phys_cursor_y != s->cursor_y + || (s->display.x->text_cursor_kind != hollow_box_cursor + && (s != x_focus_screen)))) + { + /* Erase the cursor by redrawing the character underneath it. */ + x_draw_single_glyph (s, s->phys_cursor_y, s->phys_cursor_x, + (SCREEN_CURRENT_GLYPHS (s) + ->highlight[s->phys_cursor_y])); + + s->phys_cursor_x = -1; + } + + /* If we want to show a cursor, + or we want a box cursor and it's not so, + write it in the right place. */ + if (on + && (s->phys_cursor_x < 0 + || (s->display.x->text_cursor_kind != filled_box_cursor + && s == x_focus_screen))) + { + if (s != x_focus_screen) + { + x_draw_box (s); + s->display.x->text_cursor_kind = hollow_box_cursor; + } + else + { + x_draw_single_glyph (s, s->cursor_y, s->cursor_x, 2); + s->display.x->text_cursor_kind = filled_box_cursor; + } + + s->phys_cursor_x = s->cursor_x; + s->phys_cursor_y = s->cursor_y; + } + + if (updating_screen != s) + XFlushQueue (); +} + +#if 0 +This code has been rewritten to use x_draw_single_glyph and draw +box cursors successfully. Once that code is working, this can go away. + +/* Turn the displayed cursor of screen S on or off according to ON. + If ON is nonzero, where to put the cursor is specified + by S->cursor_x and S->cursor_y. */ + +static void +x_display_box_cursor (s, on) + struct screen *s; + int on; +{ + register struct screen_glyphs *current_screen = SCREEN_CURRENT_GLYPHS (s); + + if (! s->visible) + return; + + /* If cursor is off and we want it off, return quickly. */ + + if (!on && s->phys_cursor_x < 0) + return; + + /* If cursor is currently being shown and we don't want it to be + or it is in the wrong place, erase it. */ + + if (s->phys_cursor_x >= 0 + && (!on || s->phys_cursor_x != s->cursor_x + || s->phys_cursor_y != s->cursor_y)) + { + /* If there is supposed to be a character there, redraw it + in that line's normal video. */ + if (current_screen->enable[s->phys_cursor_y] + && s->phys_cursor_x < current_screen->used[s->phys_cursor_y]) + dumpglyphs (s, + (s->phys_cursor_x * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width), + (s->phys_cursor_y * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width), + ¤t_screen->glyphs[s->phys_cursor_y][s->phys_cursor_x], + 1, current_screen->highlight[s->phys_cursor_y], + s->display.x->font); + /* Otherwise just erase the space. */ + else +#ifdef HAVE_X11 + XClearArea (x_current_display, s->display.x->window_desc, + s->phys_cursor_x * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width, + s->phys_cursor_y * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width, + FONT_WIDTH (s->display.x->font), + FONT_HEIGHT (s->display.x->font), False); +#else + XPixSet (s->display.x->window_desc, + s->phys_cursor_x * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width, + s->phys_cursor_y * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width, + FONT_WIDTH (s->display.x->font), + FONT_HEIGHT (s->display.x->font), + s->display.x->background_pixel); +#endif /* HAVE_X11 */ + + s->phys_cursor_x = -1; + } + + /* If we want to show a cursor, write it in the right place. */ + + if (on && s->phys_cursor_x < 0) + { + if (s != selected_screen || s != x_input_screen) + x_draw_box (s); + else if (current_screen->enable[s->cursor_y] + && s->cursor_x < current_screen->used[s->cursor_y]) + /* There is a character there: draw the character with + cursor coloration. */ + dumpglyphs (s, + (s->cursor_x * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width), + (s->cursor_y * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width), + ¤t_screen->glyphs[s->cursor_y][s->cursor_x], + 1, 2, s->display.x->font); + else +#ifdef HAVE_X11 + { + GLYPH space = SPACEGLYPH; + dumpglyphs (s, + (s->cursor_x * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width), + (s->cursor_y * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width), + &space, 1, + 2, s->display.x->font); + } +#if 0 + /* This kills the HP-BSD X11R3 server... */ + XFillRectangle (x_current_display, s->display.x->window_desc, + s->display.x->cursor_gc, + s->cursor_x * FONT_WIDTH (s->display.x->font) + + s->display.x->internal_border_width, + s->cursor_y * FONT_HEIGHT (s->display.x->font) + + s->display.x->internal_border_width, + FONT_WIDTH (s->display.x->font), FONT_HEIGHT (s->display.x->font)); +#endif +#else + XPixSet (s->display.x->window_desc, + s->cursor_x * FONT_WIDTH (s->display.x->font)+s->display.x->internal_border_width, + s->cursor_y * FONT_HEIGHT (s->display.x->font)+s->display.x->internal_border_width, + FONT_WIDTH (s->display.x->font), FONT_HEIGHT (s->display.x->font), s->display.x->cursor_pixel); +#endif /* HAVE_X11 */ + + s->phys_cursor_x = s->cursor_x; + s->phys_cursor_y = s->cursor_y; + } + + if (updating_screen != s) + XFlushQueue (); +} +#endif + +extern Lisp_Object Vbar_cursor; + +x_display_cursor (s, on) + struct screen *s; + int on; +{ + if (EQ (Vbar_cursor, Qnil)) + x_display_box_cursor (s, on); + else + x_display_bar_cursor (s, on); +} + +/* Icons. */ + +/* Refresh bitmap kitchen sink icon for screen S + when we get an expose event for it. */ + +refreshicon (s) + struct screen *s; +{ +#ifdef HAVE_X11 + /* Normally, the window manager handles this function. */ +#else + int mask; + + if (s->display.x->icon_bitmap_flag) + XBitmapBitsPut (s->display.x->icon_desc, 0, 0, sink_width, sink_height, + sink_bits, BlackPixel, WHITE_PIX_DEFAULT, + icon_bitmap, GXcopy, AllPlanes); + else + { + extern struct screen *selected_screen; + struct Lisp_String *str; + unsigned char *string; + + string + = XSTRING (XBUFFER (XWINDOW (s->selected_window)->buffer)->name)->data; + + if (s->display.x->icon_label != string) + { + s->display.x->icon_label = string; + XChangeWindow (s->display.x->icon_desc, + XQueryWidth (string, icon_font_info->id) + 10, + icon_font_info->height + 10); + } + + XText (s->display.x->icon_desc, 5, 5, string, + str->size, icon_font_info->id, + BLACK_PIX_DEFAULT, WHITE_PIX_DEFAULT); + } + XFlushQueue (); +#endif /* HAVE_X11 */ +} + +/* Make the x-window of screen S use the kitchen-sink icon + that's a window generated by Emacs. */ + +int +x_bitmap_icon (s) + struct screen *s; +{ + int mask; + Window icon_window; + + if (s->display.x->window_desc == 0) + return 1; + +#ifdef HAVE_X11 + if (icon_bitmap) + XFreePixmap (x_current_display, icon_bitmap); + + icon_bitmap = + XCreateBitmapFromData (x_current_display, s->display.x->window_desc, + gnu_bits, gnu_width, gnu_height); + x_wm_set_icon_pixmap (s, icon_bitmap); + s->display.x->icon_bitmap_flag = 1; +#else + if (s->display.x->icon_desc) + { + XClearIconWindow (s->display.x->window_desc); + XDestroyWindow (s->display.x->icon_desc); + } + + icon_window = XCreateWindow (s->display.x->parent_desc, + 0, 0, sink_width, sink_height, + 2, WhitePixmap, (Pixmap) NULL); + + if (icon_window == 0) + return 1; + + XSetIconWindow (s->display.x->window_desc, icon_window); + XSelectInput (icon_window, ExposeWindow | UnmapWindow); + + s->display.x->icon_desc = icon_window; + s->display.x->icon_bitmap_flag = 1; + + if (icon_bitmap == 0) + icon_bitmap + = XStoreBitmap (sink_mask_width, sink_mask_height, sink_mask_bits); +#endif /* HAVE_X11 */ + + return 0; +} + + +/* Make the x-window of screen S use a rectangle with text. */ + +int +x_text_icon (s, icon_name) + struct screen *s; + char *icon_name; +{ +#ifndef HAVE_X11 + int mask; + int width; + Window icon_window; + char *X_DefaultValue; + Bitmap b1; + +#if 0 /* This doesn't seem to be used, but I can't quite believe it. */ + static Pixmap grey_pixmap; +#endif + +#ifndef WhitePixel +#define WhitePixel 1 +#endif + +#ifndef BlackPixel +#define BlackPixel 0 +#endif +#endif /* not HAVE_X11 */ + + if (s->display.x->window_desc == 0) + return 1; + + if (icon_font_info == 0) + icon_font_info + = XGetFont (XGetDefault (XDISPLAY invocation_name, "BodyFont")); + +#ifdef HAVE_X11 + if (icon_name) + s->display.x->icon_label = icon_name; + else + if (! s->display.x->icon_label) + s->display.x->icon_label = " *emacs* "; + + XSetIconName (x_current_display, s->display.x->window_desc, + (char *) s->display.x->icon_label); + + s->display.x->icon_bitmap_flag = 0; +#else + if (s->display.x->icon_desc) + { + XClearIconWindow (XDISPLAY s->display.x->window_desc); + XDestroyWindow (XDISPLAY s->display.x->icon_desc); + } + + if (icon_name) + s->display.x->icon_label = (unsigned char *) icon_name; + else + if (! s->display.x->icon_label) + s->display.x->icon_label = XSTRING (s->name)->data; + + width = XStringWidth (s->display.x->icon_label, icon_font_info, 0, 0); + icon_window = XCreateWindow (s->display.x->parent_desc, + s->display.x->left_pos, + s->display.x->top_pos, + width + 10, icon_font_info->height + 10, + 2, BlackPixmap, WhitePixmap); + + if (icon_window == 0) + return 1; + + XSetIconWindow (s->display.x->window_desc, icon_window); + XSelectInput (icon_window, ExposeWindow | ExposeRegion | UnmapWindow | ButtonPressed); + + s->display.x->icon_desc = icon_window; + s->display.x->icon_bitmap_flag = 0; + s->display.x->icon_label = 0; +#endif /* HAVE_X11 */ + + return 0; +} + +static char *x_proto_requests[] = +{ + "CreateWindow", + "ChangeWindowAttributes", + "GetWindowAttributes", + "DestroyWindow", + "DestroySubwindows", + "ChangeSaveSet", + "ReparentWindow", + "MapWindow", + "MapSubwindows", + "UnmapWindow", + "UnmapSubwindows", + "ConfigureWindow", + "CirculateWindow", + "GetGeometry", + "QueryTree", + "InternAtom", + "GetAtomName", + "ChangeProperty", + "DeleteProperty", + "GetProperty", + "ListProperties", + "SetSelectionOwner", + "GetSelectionOwner", + "ConvertSelection", + "SendEvent", + "GrabPointer", + "UngrabPointer", + "GrabButton", + "UngrabButton", + "ChangeActivePointerGrab", + "GrabKeyboard", + "UngrabKeyboard", + "GrabKey", + "UngrabKey", + "AllowEvents", + "GrabServer", + "UngrabServer", + "QueryPointer", + "GetMotionEvents", + "TranslateCoords", + "WarpPointer", + "SetInputFocus", + "GetInputFocus", + "QueryKeymap", + "OpenFont", + "CloseFont", + "QueryFont", + "QueryTextExtents", + "ListFonts", + "ListFontsWithInfo", + "SetFontPath", + "GetFontPath", + "CreatePixmap", + "FreePixmap", + "CreateGC", + "ChangeGC", + "CopyGC", + "SetDashes", + "SetClipRectangles", + "FreeGC", + "ClearArea", + "CopyArea", + "CopyPlane", + "PolyPoint", + "PolyLine", + "PolySegment", + "PolyRectangle", + "PolyArc", + "FillPoly", + "PolyFillRectangle", + "PolyFillArc", + "PutImage", + "GetImage", + "PolyText", + "PolyText", + "ImageText", + "ImageText", + "CreateColormap", + "FreeColormap", + "CopyColormapAndFree", + "InstallColormap", + "UninstallColormap", + "ListInstalledColormaps", + "AllocColor", + "AllocNamedColor", + "AllocColorCells", + "AllocColorPlanes", + "FreeColors", + "StoreColors", + "StoreNamedColor", + "QueryColors", + "LookupColor", + "CreateCursor", + "CreateGlyphCursor", + "FreeCursor", + "RecolorCursor", + "QueryBestSize", + "QueryExtension", + "ListExtensions", + "ChangeKeyboardMapping", + "GetKeyboardMapping", + "ChangeKeyboardControl", + "GetKeyboardControl", + "Bell", + "ChangePointerControl", + "GetPointerControl", + "SetScreenSaver", + "GetScreenSaver", + "ChangeHosts", + "ListHosts", + "SetAccessControl", + "SetCloseDownMode", + "KillClient", + "RotateProperties", + "ForceScreenSaver", + "SetPointerMapping", + "GetPointerMapping", + "SetModifierMapping", + "GetModifierMapping", + "NoOperation" +}; + +#define acceptable_x_error_p(type) ((type) == 94) + +x_handle_error_gracefully (event) + XErrorEvent *event; +{ + char error_ptr[128]; + char *proto_ptr = x_proto_requests[event->request_code]; + char str[128]; + + XGetErrorText (x_current_display, event->error_code, error_ptr, 128); + sprintf (str, "X Protocol Error: %s on request: %s", error_ptr, proto_ptr); + TOTALLY_UNBLOCK_INPUT; + error (str); +} + +#if 0 +extern int x_selection_alloc_error; +extern int x_converting_selection; +#endif + +/* Handle X Errors. If the error is not traumatic, + just call error (). Otherwise print a (hopefully) interesting + message and quit. + + The arg to Fkill_emacs is an exit status value + and also prevents any questions. */ + +x_error_handler (disp, event) + Display *disp; +#ifdef HAVE_X11 + XErrorEvent *event; + +#define XlibDisplayIOError (1L << 0) + +#else + struct _XErrorEvent *event; +#endif +{ + /* Here we use the standard X handlers. */ + + BLOCK_INPUT; + if (event && event->type == 0) /* 0 is the XError Event type. */ + { +#if 0 +#ifdef HAVE_X11 + if (event->request_code == BadAlloc && x_converting_selection) + x_selection_alloc_error = 1; + else +#endif +#endif + if (acceptable_x_error_p (event->request_code)) + x_handle_error_gracefully (event); + else + _XDefaultError (disp, event); + } + else + { + disp->flags |= XlibDisplayIOError; + _XDefaultIOError (disp); + } + UNBLOCK_INPUT; + + if (_Xdebug) + abort (); + else + Fkill_emacs (make_number (70)); +} + +/* Initialize communication with the X window server. */ + +#if 0 +static unsigned int x_wire_count; +x_trace_wire () +{ + fprintf (stderr, "Lib call: %d\n", ++x_wire_count); +} +#endif + + +/* Set the font of the x-window specified by screen S + to the font named NEWNAME. This is safe to use + even before S has an actual x-window. */ + +#ifdef HAVE_X11 + +/* A table of all the fonts we have already loaded. */ +static XFontStruct **x_font_table; + +/* The current capacity of x_font_table. */ +static int x_font_table_size; + +/* The number of fonts actually stored in x_font_table. + x_font_table[n] is used and valid iff 0 <= n < n_fonts. + 0 <= n_fonts <= x_font_table_size. */ +static int n_fonts; + +x_new_font (s, fontname) + struct screen *s; + register char *fontname; +{ + XFontStruct *temp; + int already_loaded; + int n_matching_fonts; + XFontStruct *font_info; + char **font_names; + + /* Get a list of all the fonts that match this name. Once we + have a list of matching fonts, we compare them against the fonts + we already have by comparing font ids. */ + font_names = (char **) XListFontsWithInfo (x_current_display, fontname, + 1024, &n_matching_fonts, + &font_info); + /* If the server couldn't find any fonts whose named matched fontname, + return an error code. */ + if (n_matching_fonts == 0) + return 1; + + /* See if we've already loaded this font. */ + { + int i, j; + + already_loaded = 0; + for (i = 0; i < n_fonts; i++) + for (j = 0; j < n_matching_fonts; j++) + if (x_font_table[i]->fid == font_info[j].fid) + { + already_loaded = i; + goto found_font; + } + } + found_font: + + /* If we have, just return it from the table. */ + if (already_loaded) + { + s->display.x->font = x_font_table[already_loaded]; + } + + /* Otherwise, load the font and add it to the table. */ + else + { + XFontStruct *font; + + font = (XFontStruct *) XLoadQueryFont (x_current_display, fontname); + if (! font) + return 1; + + /* Do we need to create the table? */ + if (x_font_table_size == 0) + { + x_font_table_size = 16; + x_font_table + = (XFontStruct **) xmalloc (x_font_table_size + * sizeof (x_font_table[0])); + } + /* Do we need to grow the table? */ + else if (n_fonts >= x_font_table_size) + { + x_font_table_size <<= 1; + x_font_table + = (XFontStruct **) xrealloc (x_font_table, + (x_font_table_size + * sizeof (x_font_table[0]))); + } + + s->display.x->font = x_font_table[n_fonts++] = font; + } + + /* Free the information from XListFontsWithInfo. The data + we actually retain comes from XLoadQueryFont. */ + XFreeFontInfo (font_names, font_info, n_matching_fonts); + + /* Now make the screen display the given font. */ + if (s->display.x->window_desc != 0) + { + XSetFont (x_current_display, s->display.x->normal_gc, + s->display.x->font->fid); + XSetFont (x_current_display, s->display.x->reverse_gc, + s->display.x->font->fid); + XSetFont (x_current_display, s->display.x->cursor_gc, + s->display.x->font->fid); + + x_set_window_size (s, s->width, s->height); + } + + return 0; +} +#else +x_new_font (s, newname) + struct screen *s; + register char *newname; +{ + FONT_TYPE *temp; + int mask; + + temp = XGetFont (newname); + if (temp == (FONT_TYPE *) 0) + return 1; + + if (s->display.x->font) + XLoseFont (s->display.x->font); + + s->display.x->font = temp; + + if (s->display.x->window_desc != 0) + x_set_window_size (s, s->width, s->height); + + return 0; +} +#endif + +x_calc_absolute_position (s) + struct screen *s; +{ +#ifdef HAVE_X11 + if (s->display.x->left_pos < 0) + s->display.x->left_pos + = XINT (x_screen_width) - PIXEL_WIDTH (s) + s->display.x->left_pos; + + if (s->display.x->top_pos < 0) + s->display.x->top_pos + = XINT (x_screen_height) - PIXEL_HEIGHT (s) + s->display.x->top_pos; +#else /* X10 */ + WINDOWINFO_TYPE parentinfo; + + XGetWindowInfo (s->display.x->window_desc, &parentinfo); + + if (s->display.x->left_pos < 0) + s->display.x->left_pos = parentinfo.width + (s->display.x->left_pos + 1) + - PIXEL_WIDTH (s) - 2 * s->display.x->internal_border_width; + + if (s->display.x->top_pos < 0) + s->display.x->top_pos = parentinfo.height + (s->display.x->top_pos + 1) + - PIXEL_HEIGHT (s) - 2 * s->display.x->internal_border_width; +#endif /* X10 */ +} + +x_set_offset (s, xoff, yoff) + struct screen *s; + register int xoff, yoff; +{ + s->display.x->top_pos = yoff; + s->display.x->left_pos = xoff; + x_calc_absolute_position (s); + + BLOCK_INPUT; + XMoveWindow (XDISPLAY s->display.x->window_desc, + s->display.x->left_pos, s->display.x->top_pos); +#ifdef HAVE_X11 + x_wm_set_size_hint (s, 0); +#endif + UNBLOCK_INPUT; +} + +/* Call this to change the size of screen S's x-window. */ + +x_set_window_size (s, cols, rows) + struct screen *s; + register int cols, rows; +{ + int pixelwidth, pixelheight; + int mask; + int ibw = s->display.x->internal_border_width; + + BLOCK_INPUT; + + /* ??? Who DOES worry about minimum reasonable sizes? */ + pixelwidth = (cols * FONT_WIDTH (s->display.x->font) + 2 * ibw + + s->display.x->v_scrollbar_width); + pixelheight = (rows * FONT_HEIGHT (s->display.x->font) + 2 * ibw + + s->display.x->h_scrollbar_height); + +#ifdef HAVE_X11 + x_wm_set_size_hint (s, 0); +#endif /* HAVE_X11 */ + XChangeWindowSize (s->display.x->window_desc, pixelwidth, pixelheight); + XFlushQueue (); + UNBLOCK_INPUT; +} + +#ifndef HAVE_X11 +x_set_resize_hint (s) + struct screen *s; +{ + + XSetResizeHint (s->display.x->window_desc, 2 * s->display.x->internal_border_width, + 2 * s->display.x->internal_border_width, + FONT_WIDTH (s->display.x->font), FONT_HEIGHT (s->display.x->font)); +} +#endif /* not HAVE_X11 */ + + +x_set_mouse_position (s, x, y) + struct screen *s; + int x, y; +{ + int pix_x, pix_y; + + x_raise_screen (s); + + if (x < 0) + pix_x = (SCREEN_WIDTH (s) + * FONT_WIDTH (s->display.x->font) + + 2 * s->display.x->internal_border_width + + s->display.x->v_scrollbar_width) / 2; + else + pix_x = x * FONT_WIDTH (s->display.x->font) + 2; /* add 2 pixels to each + dimension to move the + mouse into the char + cell */ + + if (y < 0) + pix_y = (SCREEN_HEIGHT (s) + * FONT_HEIGHT (s->display.x->font) + + 2 * s->display.x->internal_border_width + + s->display.x->h_scrollbar_height) / 2; + else + pix_y = y * FONT_HEIGHT (s->display.x->font) + 2; + + BLOCK_INPUT; + x_mouse_x = x; + x_mouse_y = y; + + XWarpMousePointer (s->display.x->window_desc, pix_x, pix_y); + UNBLOCK_INPUT; +} + +#ifdef HAVE_X11 +x_focus_on_screen (s) + struct screen *s; +{ + x_raise_screen (s); + XSetInputFocus (x_current_display, s->display.x->window_desc, + RevertToPointerRoot, CurrentTime); +} + +x_unfocus_screen (s) + struct screen *s; +{ + if (x_focus_screen == s) + XSetInputFocus (x_current_display, PointerRoot, + RevertToPointerRoot, CurrentTime); +} + +#endif + +/* Raise screen S. */ + +x_raise_screen (s) + struct screen *s; +{ + if (s->visible) + { + BLOCK_INPUT; + XRaiseWindow (XDISPLAY s->display.x->window_desc); + XFlushQueue (); + UNBLOCK_INPUT; + } +} + +/* Lower screen S. */ + +x_lower_screen (s) + struct screen *s; +{ + if (s->visible) + { + BLOCK_INPUT; + XLowerWindow (XDISPLAY s->display.x->window_desc); + XFlushQueue (); + UNBLOCK_INPUT; + } +} + +/* Change from withdrawn state to mapped state. */ + +x_make_screen_visible (s) + struct screen *s; +{ + int mask; + + if (s->visible) + { + BLOCK_INPUT; + XRaiseWindow (XDISPLAY s->display.x->window_desc); + XFlushQueue (); + UNBLOCK_INPUT; + return; + } + + BLOCK_INPUT; +#ifdef HAVE_X11 + + if (! EQ (Vx_no_window_manager, Qt)) + x_wm_set_window_state (s, NormalState); + + XMapWindow (XDISPLAY s->display.x->window_desc); + if (s->display.x->v_scrollbar != 0 || s->display.x->h_scrollbar != 0) + XMapSubwindows (x_current_display, s->display.x->window_desc); + +#else + XMapWindow (XDISPLAY s->display.x->window_desc); + if (s->display.x->icon_desc != 0) + XUnmapWindow (s->display.x->icon_desc); + + /* Handled by the MapNotify event for X11 */ + s->visible = 1; + s->iconified = 0; + + /* NOTE: this may cause problems for the first screen. */ + XTcursor_to (0, 0); +#endif /* not HAVE_X11 */ + + XRaiseWindow (XDISPLAY s->display.x->window_desc); + XFlushQueue (); + UNBLOCK_INPUT; +} + +/* Change from mapped state to withdrawn state. */ + +x_make_screen_invisible (s) + struct screen *s; +{ + int mask; + + if (! s->visible) + return; + + BLOCK_INPUT; +#ifdef HAVE_X11 +#if 0 + if (! EQ (Vx_no_window_manager, Qt)) + { + XUnmapEvent unmap; + + unmap.type = UnmapNotify; + unmap.window = s->display.x->window_desc; + unmap.event = DefaultRootWindow (x_current_display); + unmap.from_configure = False; + XSendEvent (x_current_display, DefaultRootWindow (x_current_display), + False, SubstructureRedirectMask|SubstructureNotifyMask, + &unmap); + } + + /* The new function below does the same as the above code, plus unmapping + the window. Sending the event without actually unmapping can make + the window manager start ignoring the window (i.e., no more title bar, + icon manager stuff.) */ +#endif + + /* New function available with R4 */ + if (! XWithdrawWindow (x_current_display, s->display.x->window_desc, + DefaultScreen (x_current_display))) + { + UNBLOCK_INPUT_RESIGNAL; + error ("Can't notify window manager of iconification."); + } + +#else + XUnmapWindow (XDISPLAY s->display.x->window_desc); + + s->visible = 0; /* Handled by the UnMap event for X11 */ + if (s->display.x->icon_desc != 0) + XUnmapWindow (XDISPLAY s->display.x->icon_desc); +#endif /* not HAVE_X11 */ + + XFlushQueue (); + UNBLOCK_INPUT; +} + + /* Window manager communication. Created in Fx_open_connection. */ +extern Atom Xatom_wm_change_state; + +/* Change window state from mapped to iconified. */ + +x_iconify_screen (s) + struct screen *s; +{ + int mask; + + if (s->iconified) + return; + + BLOCK_INPUT; + +#ifdef HAVE_X11 + if (! EQ (Vx_no_window_manager, Qt)) + if (! XIconifyWindow (x_current_display, s->display.x->window_desc, + DefaultScreen (x_current_display))) + { + UNBLOCK_INPUT_RESIGNAL; + error ("Can't notify window manager of iconification."); + } + + s->iconified = 1; + +#if 0 + { + XClientMessageEvent message; + + message.window = s->display.x->window_desc; + message.type = ClientMessage; + message.message_type = Xatom_wm_change_state; + message.format = 32; + message.data.l[0] = IconicState; + + if (! XSendEvent (x_current_display, + DefaultRootWindow (x_current_display), + False, + SubstructureRedirectMask | SubstructureNotifyMask, + &message)) + { + UNBLOCK_INPUT_RESIGNAL; + error ("Can't notify window manager of iconification."); + } + } +#endif +#else /* X10 */ + XUnmapWindow (XDISPLAY s->display.x->window_desc); + + s->visible = 0; /* Handled in the UnMap event for X11. */ + if (s->display.x->icon_desc != 0) + { + XMapWindow (XDISPLAY s->display.x->icon_desc); + refreshicon (s); + } +#endif /* X10 */ + + XFlushQueue (); + UNBLOCK_INPUT; +} + +/* Destroy the X window of screen S. + DISPL is the former s->display (since s->display + has already been nulled out). */ + +x_destroy_window (s, displ) + struct screen *s; + union display displ; +{ + int mask; + + BLOCK_INPUT; + if (displ.x->icon_desc != 0) + XDestroyWindow (XDISPLAY displ.x->icon_desc); + XDestroyWindow (XDISPLAY displ.x->window_desc); + XFlushQueue (); + UNBLOCK_INPUT; + + free (displ.x); + if (s == x_focus_screen) + x_focus_screen = 0; +} + +#ifndef HAVE_X11 + +/* Manage event queues. + + This code is only used by the X10 support. + + We cannot leave events in the X queue and get them when we are ready + because X does not provide a subroutine to get only a certain kind + of event but not block if there are no queued events of that kind. + + Therefore, we must examine events as they come in and copy events + of certain kinds into our private queues. + + All ExposeRegion events are put in x_expose_queue. + All ButtonPressed and ButtonReleased events are put in x_mouse_queue. */ + + +/* Write the event *P_XREP into the event queue *QUEUE. + If the queue is full, do nothing, but return nonzero. */ + +int +enqueue_event (p_xrep, queue) + register XEvent *p_xrep; + register struct event_queue *queue; +{ + int newindex = queue->windex + 1; + if (newindex == EVENT_BUFFER_SIZE) + newindex = 0; + if (newindex == queue->rindex) + return -1; + queue->xrep[queue->windex] = *p_xrep; + queue->windex = newindex; + return 0; +} + +/* Fetch the next event from queue *QUEUE and store it in *P_XREP. + If *QUEUE is empty, do nothing and return 0. */ + +int +dequeue_event (p_xrep, queue) + register XEvent *p_xrep; + register struct event_queue *queue; +{ + if (queue->windex == queue->rindex) + return 0; + *p_xrep = queue->xrep[queue->rindex++]; + if (queue->rindex == EVENT_BUFFER_SIZE) + queue->rindex = 0; + return 1; +} + +/* Return the number of events buffered in *QUEUE. */ + +int +queue_event_count (queue) + register struct event_queue *queue; +{ + int tem = queue->windex - queue->rindex; + if (tem >= 0) + return tem; + return EVENT_BUFFER_SIZE + tem; +} + +/* Return nonzero if mouse input is pending. */ + +int +mouse_event_pending_p () +{ + return queue_event_count (&x_mouse_queue); +} +#endif + +#ifdef HAVE_X11 + +x_wm_set_size_hint (s, prompting) + struct screen *s; + long prompting; +{ + XSizeHints size_hints; + Window window = s->display.x->window_desc; + + size_hints.flags = PResizeInc | PMinSize | PMaxSize; + + flexlines = s->height; + + size_hints.x = s->display.x->left_pos; + size_hints.y = s->display.x->top_pos; + size_hints.height = PIXEL_HEIGHT (s); + size_hints.width = PIXEL_WIDTH (s); + size_hints.width_inc = FONT_WIDTH (s->display.x->font); + size_hints.height_inc = FONT_HEIGHT (s->display.x->font); + size_hints.base_width = (2 * s->display.x->internal_border_width) + + s->display.x->v_scrollbar_width; + size_hints.base_height = (2 * s->display.x->internal_border_width) + + s->display.x->h_scrollbar_height; + size_hints.min_width = size_hints.base_width + size_hints.width_inc; + size_hints.min_height = size_hints.base_height + size_hints.height_inc; + size_hints.max_width = x_screen_width + - ((2 * s->display.x->internal_border_width) + + s->display.x->v_scrollbar_width); + size_hints.max_height = x_screen_height + - ((2 * s->display.x->internal_border_width) + + s->display.x->h_scrollbar_height); + + if (prompting) + size_hints.flags |= prompting; + else + { + XSizeHints hints; /* Sometimes I hate X Windows... */ + + XGetNormalHints (x_current_display, window, &hints); + if (hints.flags & PSize) + size_hints.flags |= PSize; + if (hints.flags & PPosition) + size_hints.flags |= PPosition; + if (hints.flags & USPosition) + size_hints.flags |= USPosition; + if (hints.flags & USSize) + size_hints.flags |= USSize; + } + +#if 0 /* R3 */ + XSetNormalHints (x_current_display, window, &size_hints); +#endif + XSetWMNormalHints (x_current_display, window, &size_hints); +} + +/* Used for IconicState or NormalState */ +x_wm_set_window_state (s, state) + struct screen *s; + int state; +{ + XWMHints wm_hints; + Window window = s->display.x->window_desc; + + wm_hints.flags = StateHint; + wm_hints.initial_state = state; + XSetWMHints (x_current_display, window, &wm_hints); +} + +x_wm_set_icon_pixmap (s, icon_pixmap) + struct screen *s; + Pixmap icon_pixmap; +{ + XWMHints wm_hints; + Window window = s->display.x->window_desc; + + wm_hints.flags = IconPixmapHint; + wm_hints.icon_pixmap = icon_pixmap; + XSetWMHints (x_current_display, window, &wm_hints); +} + +x_wm_set_icon_position (s, icon_x, icon_y) + struct screen *s; + int icon_x, icon_y; +{ + XWMHints wm_hints; + Window window = s->display.x->window_desc; + + wm_hints.flags = IconPositionHint; + wm_hints.icon_x = icon_x; + wm_hints.icon_y = icon_y; + XSetWMHints (x_current_display, window, &wm_hints); +} + + +static void +init_input_symbols () +{ + Qmapped_screen = intern ("mapped-screen"); + Qunmapped_screen = intern ("unmapped-screen"); + Qexited_scrollbar = intern ("exited-scrollbar"); + Qexited_window = intern ("exited-window"); + Qredraw_screen = intern ("redraw-screen"); + Qmouse_moved = intern ("mouse-moved"); + Qmouse_click = intern ("mouse-click"); + Qscrollbar_click = intern ("scrollbar-click"); +} + +void +x_term_init (display_name) + char *display_name; +{ + Lisp_Object screen; + char *defaultvalue; +#ifdef F_SETOWN + extern int old_fcntl_owner; +#endif + + x_current_display = XOpenDisplay (display_name); + if (x_current_display == 0) + fatal ("X server %s not responding; check the DISPLAY environment variable or use \"-d\"\n", + display_name); + +#ifdef HAVE_X11 + { + int hostname_size = MAXHOSTNAMELEN + 1; + + hostname = (char *) xmalloc (hostname_size); + +#if 0 + XSetAfterFunction (x_current_display, x_trace_wire); +#endif + + invocation_name = (char *) + XSTRING (Ffile_name_nondirectory (Fcar (Vcommand_line_args)))->data; + + /* Try to get the host name; if the buffer is too short, try + again. Apparently, the only indication gethostname gives of + whether the buffer was large enough is the presence or absence + of a '\0' in the string. Eech. */ + for (;;) + { + gethostname (hostname, hostname_size - 1); + hostname[hostname_size - 1] = '\0'; + + /* Was the buffer large enough for gethostname to store the '\0'? */ + if (strlen (hostname) < hostname_size - 1) + break; + + hostname_size <<= 1; + hostname = (char *) xrealloc (hostname, hostname_size); + } + id_name = (char *) xmalloc (strlen (invocation_name) + + strlen (hostname) + + 2); + sprintf (id_name, "%s@%s", invocation_name, hostname); + } + + dup2 (ConnectionNumber (x_current_display), 0); + close (ConnectionNumber (x_current_display)); + ConnectionNumber (x_current_display) = 0; +#endif /* HAVE_X11 */ + +#ifdef F_SETOWN + old_fcntl_owner = fcntl (0, F_GETOWN, 0); +#ifdef F_SETOWN_SOCK_NEG + fcntl (0, F_SETOWN, -getpid ()); /* stdin is a socket here */ +#else + fcntl (0, F_SETOWN, getpid ()); +#endif /* F_SETOWN_SOCK_NEG */ +#endif /* F_SETOWN */ + +#ifdef SIGIO + init_sigio (); +#endif + + /* Must use interrupt input because we cannot otherwise + arrange for C-g to be noticed immediately. + We cannot connect it to SIGINT. */ + Fset_input_mode (Qt, Qnil, Qt, Qnil); + + expose_all_windows = 0; + + clear_screen_hook = XTclear_screen; + clear_end_of_line_hook = XTclear_end_of_line; + ins_del_lines_hook = XTins_del_lines; + change_line_highlight_hook = XTchange_line_highlight; + insert_glyphs_hook = XTinsert_glyphs; + write_glyphs_hook = XTwrite_glyphs; + delete_glyphs_hook = XTdelete_glyphs; + ring_bell_hook = XTring_bell; + reset_terminal_modes_hook = XTreset_terminal_modes; + set_terminal_modes_hook = XTset_terminal_modes; + update_begin_hook = XTupdate_begin; + update_end_hook = XTupdate_end; + set_terminal_window_hook = XTset_terminal_window; + read_socket_hook = XTread_socket; + cursor_to_hook = XTcursor_to; + reassert_line_highlight_hook = XTreassert_line_highlight; + mouse_tracking_enable_hook = XTmouse_tracking_enable; + + scroll_region_ok = 1; /* we'll scroll partial screens */ + char_ins_del_ok = 0; /* just as fast to write the line */ + line_ins_del_ok = 1; /* we'll just blt 'em */ + fast_clear_end_of_line = 1; /* X does this well */ + memory_below_screen = 0; /* we don't remember what scrolls + off the bottom */ + baud_rate = 19200; + + init_input_symbols (); + + XHandleError (x_error_handler); + XHandleIOError (x_error_handler); + + /* Disable Window Change signals; they are handled by X events. */ +#ifdef SIGWINCH + signal (SIGWINCH, SIG_DFL); +#endif /* SIGWINCH */ + + signal (SIGPIPE, x_error_handler); +} +#endif /* HAVE_X11 */ +#endif /* HAVE_X_WINDOWS */