/* Functions for the X window system.
Copyright (C) 1988, 1990 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)
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. */
/* Written by Yakim Martillo; rearranged by Richard Stallman. */
/* Color and other features added by Robert Krawitz*/
/* Converted to X11 by Robert French */
/* Get FIONREAD, if it is available. */
/* Allow m- file to inhibit use of interrupt-driven input. */
/* We are unable to use interrupts if FIONREAD is not available,
so flush SIGIO so we won't try. */
#define abs(x) ((x < 0) ? ((x)) : (x))
#define sgn(x) ((x < 0) ? (-1) : (1))
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
/* Non-nil if Emacs is running with an X window for display.
Nil if Emacs is run on an ordinary terminal. */
Lisp_Object Vx_mouse_pos
;
Lisp_Object Vx_mouse_abs_pos
;
Lisp_Object Vx_mouse_item
;
extern Lisp_Object MouseMap
;
extern Lisp_Object minibuf_window
;
extern int minibuf_prompt_width
;
extern XEvent
*XXm_queue
[XMOUSEBUFSIZE
];
extern int XXm_queue_num
;
extern int XXm_queue_out
;
extern unsigned long fore
;
extern unsigned long back
;
extern unsigned long brdr
;
extern unsigned long curs
;
extern int XXInternalBorder
;
extern XFontStruct
*fontinfo
;
extern GC XXgc_norm
,XXgc_rev
,XXgc_curs
,XXgc_temp
;
extern int XXfontw
,XXfonth
,XXbase
,XXisColor
;
extern Colormap XXColorMap
;
extern int PendingExposure
;
extern char *default_window
;
extern char *desiredwindow
;
extern Cursor EmacsCursor
;
extern short MouseCursor
[], MouseMask
[];
extern char *XXcurrentfont
;
extern int pixelwidth
, pixelheight
;
extern Display
*XXdisplay
;
extern int bitblt
, CursorExists
, VisibleX
, VisibleY
;
error ("Terminal does not understand X protocol.");
DEFUN ("x-set-bell", Fx_set_bell
, Sx_set_bell
, 1, 1, "P",
"For X window system, set audible vs visible bell.\n\
With non-nil argument (prefix arg), use visible bell; otherwise, audible bell.")
DEFUN ("x-flip-color", Fx_flip_color
, Sx_flip_color
, 0, 0, "",
"Toggle the background and foreground colors")
DEFUN ("x-set-foreground-color", Fx_set_foreground_color
,
Sx_set_foreground_color
, 1, 1, "sSet foregroud color: ",
"Set foreground (text) color to COLOR.")
fore_color
= (char *) xmalloc (XSTRING (arg
)->size
+ 1);
bcopy (XSTRING (arg
)->data
, fore_color
, XSTRING (arg
)->size
+ 1);
if (fore_color
&& XXisColor
&&
XParseColor (XXdisplay
, XXColorMap
, fore_color
, &cdef
) &&
XAllocColor(XXdisplay
, XXColorMap
, &cdef
))
if (fore_color
&& !strcmp (fore_color
, "black"))
fore
= BlackPixel (XXdisplay
, XXscreen
);
if (fore_color
&& !strcmp (fore_color
, "white"))
fore
= WhitePixel (XXdisplay
, XXscreen
);
XSetForeground(XXdisplay
, XXgc_norm
, fore
);
XSetBackground(XXdisplay
, XXgc_rev
, fore
);
DEFUN ("x-set-background-color", Fx_set_background_color
,
Sx_set_background_color
, 1, 1, "sSet background color: ",
"Set background color to COLOR.")
back_color
= (char *) xmalloc (XSTRING (arg
)->size
+ 1);
bcopy (XSTRING (arg
)->data
, back_color
, XSTRING (arg
)->size
+ 1);
if (back_color
&& XXisColor
&&
XParseColor (XXdisplay
, XXColorMap
, back_color
, &cdef
) &&
XAllocColor(XXdisplay
, XXColorMap
, &cdef
))
if (back_color
&& !strcmp (back_color
, "white"))
back
= WhitePixel (XXdisplay
, XXscreen
);
if (back_color
&& !strcmp (back_color
, "black"))
back
= BlackPixel (XXdisplay
, XXscreen
);
XSetBackground (XXdisplay
, XXgc_norm
, back
);
XSetForeground (XXdisplay
, XXgc_rev
, back
);
XSetForeground (XXdisplay
, XXgc_curs
, back
);
XSetWindowBackground(XXdisplay
, XXwindow
, back
);
XClearArea (XXdisplay
, XXwindow
, 0, 0,
screen_width
*XXfontw
+2*XXInternalBorder
,
screen_height
*XXfonth
+2*XXInternalBorder
, 0);
DEFUN ("x-set-border-color", Fx_set_border_color
, Sx_set_border_color
, 1, 1,
"Set border color to COLOR.")
brdr_color
= (char *) xmalloc (XSTRING (arg
)->size
+ 1);
bcopy (XSTRING (arg
)->data
, brdr_color
, XSTRING (arg
)->size
+ 1);
if (brdr_color
&& XXisColor
&&
XParseColor (XXdisplay
, XXColorMap
, brdr_color
, &cdef
) &&
XAllocColor(XXdisplay
, XXColorMap
, &cdef
))
if (brdr_color
&& !strcmp (brdr_color
, "black"))
brdr
= BlackPixel (XXdisplay
, XXscreen
);
if (brdr_color
&& !strcmp (brdr_color
, "white"))
brdr
= WhitePixel (XXdisplay
, XXscreen
);
brdr
= BlackPixel (XXdisplay
, XXscreen
);
XSetWindowBorder(XXdisplay
, XXwindow
, brdr
);
DEFUN ("x-set-cursor-color", Fx_set_cursor_color
, Sx_set_cursor_color
, 1, 1,
"sSet text cursor color: ",
"Set text cursor color to COLOR.")
curs_color
= (char *) xmalloc (XSTRING (arg
)->size
+ 1);
bcopy (XSTRING (arg
)->data
, curs_color
, XSTRING (arg
)->size
+ 1);
if (curs_color
&& XXisColor
&&
XParseColor (XXdisplay
, XXColorMap
, curs_color
, &cdef
) &&
XAllocColor(XXdisplay
, XXColorMap
, &cdef
))
if (curs_color
&& !strcmp (curs_color
, "black"))
curs
= BlackPixel (XXdisplay
, XXscreen
);
if (curs_color
&& !strcmp (curs_color
, "white"))
curs
= WhitePixel (XXdisplay
, XXscreen
);
XSetBackground(XXdisplay
, XXgc_curs
, curs
);
DEFUN ("x-set-mouse-color", Fx_set_mouse_color
, Sx_set_mouse_color
, 1, 1,
"sSet mouse cursor color: ",
"Set mouse cursor color to COLOR.")
mous_color
= (char *) xmalloc (XSTRING (arg
)->size
+ 1);
bcopy (XSTRING (arg
)->data
, mous_color
, XSTRING (arg
)->size
+ 1);
if (! x_set_cursor_colors ())
/* Set the actual X cursor colors from `mous_color' and `back_color'. */
/* USEBACK is the background color, but on monochrome screens
changed if necessary not to match the mouse. */
if (!XXisColor
&& !strcmp (mous_color
, back_color
))
if (strcmp (back_color
, "white"))
if (XXisColor
&& mous_color
&& XParseColor (XXdisplay
, XXColorMap
, mous_color
, &forec
)
&& XParseColor (XXdisplay
, XXColorMap
, useback
, &backc
))
XRecolorCursor (XXdisplay
, EmacsCursor
, &forec
, &backc
);
DEFUN ("x-color-p", Fx_color_p
, Sx_color_p
, 0, 0, 0,
"Returns t if the display is a color X terminal.")
DEFUN ("x-get-foreground-color", Fx_get_foreground_color
,
Sx_get_foreground_color
, 0, 0, 0,
"Returns the color of the foreground, as a string.")
string
= build_string (fore_color
);
DEFUN ("x-get-background-color", Fx_get_background_color
,
Sx_get_background_color
, 0, 0, 0,
"Returns the color of the background, as a string.")
string
= build_string (back_color
);
DEFUN ("x-get-border-color", Fx_get_border_color
,
Sx_get_border_color
, 0, 0, 0,
"Returns the color of the border, as a string.")
string
= build_string (brdr_color
);
DEFUN ("x-get-cursor-color", Fx_get_cursor_color
,
Sx_get_cursor_color
, 0, 0, 0,
"Returns the color of the cursor, as a string.")
string
= build_string (curs_color
);
DEFUN ("x-get-mouse-color", Fx_get_mouse_color
,
Sx_get_mouse_color
, 0, 0, 0,
"Returns the color of the mouse cursor, as a string.")
string
= build_string (mous_color
);
DEFUN ("x-get-default", Fx_get_default
, Sx_get_default
, 1, 1, 0,
"Get default for X-window attribute ATTRIBUTE from the system.\n\
ATTRIBUTE must be a string.\n\
Returns nil if attribute default isn't specified.")
char *default_name
, *value
;
default_name
= (char *) XSTRING (arg
)->data
;
/* Some versions of X11R4, at least, have the args backwards. */
if (XXidentity
&& *XXidentity
)
value
= XGetDefault (XXdisplay
, default_name
, XXidentity
);
value
= XGetDefault (XXdisplay
, default_name
, CLASS
);
if (XXidentity
&& *XXidentity
)
value
= XGetDefault (XXdisplay
, XXidentity
, default_name
);
value
= XGetDefault (XXdisplay
, CLASS
, default_name
);
return build_string (value
);
DEFUN ("x-set-font", Fx_set_font
, Sx_set_font
, 1, 1, "sFont Name: ",
"Sets the font to be used for the X window.")
register char *newfontname
;
newfontname
= (char *) xmalloc (XSTRING (arg
)->size
+ 1);
bcopy (XSTRING (arg
)->data
, newfontname
, XSTRING (arg
)->size
+ 1);
if (XSTRING (arg
)->size
== 0)
if (!XNewFont (newfontname
)) {
XXcurrentfont
= newfontname
;
error ("Font \"%s\" is not defined", newfontname
);
DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p
,
Scoordinates_in_window_p
, 2, 2, 0,
"Return non-nil if POSITIONS (a list, (SCREEN-X SCREEN-Y)) is in WINDOW.\n\
Returned value is list of positions expressed\n\
relative to window upper left corner.")
register Lisp_Object coordinate
, window
;
register Lisp_Object xcoord
, ycoord
;
wrong_type_argument (Qlistp
, coordinate
);
CHECK_WINDOW (window
, 2);
xcoord
= Fcar (coordinate
);
ycoord
= Fcar (Fcdr (coordinate
));
CHECK_NUMBER (xcoord
, 0);
CHECK_NUMBER (ycoord
, 1);
if ((XINT (xcoord
) < XINT (XWINDOW (window
)->left
)) ||
(XINT (xcoord
) >= (XINT (XWINDOW (window
)->left
) +
XINT (XWINDOW (window
)->width
))))
XFASTINT (xcoord
) -= XFASTINT (XWINDOW (window
)->left
);
height
= XINT (XWINDOW (window
)->height
);
if (window
== minibuf_window
)
XFASTINT (xcoord
) -= minibuf_prompt_width
;
if ((XINT (ycoord
) < XINT (XWINDOW (window
)->top
)) ||
(XINT (ycoord
) >= XINT (XWINDOW (window
)->top
) + height
))
XFASTINT (ycoord
) -= XFASTINT (XWINDOW (window
)->top
);
return Fcons (xcoord
, Fcons (ycoord
, Qnil
));
DEFUN ("x-mouse-events", Fx_mouse_events
, Sx_mouse_events
, 0, 0, 0,
"Return number of pending mouse events from X window system.")
register Lisp_Object tem
;
XSET (tem
, Lisp_Int
, XXm_queue_num
);
DEFUN ("x-proc-mouse-event", Fx_proc_mouse_event
, Sx_proc_mouse_event
,
"Pulls a mouse event out of the mouse event buffer and dispatches\n\
the appropriate function to act upon this event.")
register Lisp_Object mouse_cmd
;
register char com_letter
;
register Lisp_Object tempx
;
register Lisp_Object tempy
;
extern Lisp_Object
get_keyelt ();
extern int meta_prefix_char
;
event
= *XXm_queue
[XXm_queue_out
];
free (XXm_queue
[XXm_queue_out
]);
XXm_queue_out
= (XXm_queue_out
+ 1) % XMOUSEBUFSIZE
;
com_letter
= 3-(event
.xbutton
.button
& 3);
key_mask
= (event
.xbutton
.state
& 15) << 4;
/* Report meta in 2 bit, not in 8 bit. */
if (event
.type
== ButtonRelease
)
max (0, (event
.xbutton
.x
-XXInternalBorder
)/
max (0, (event
.xbutton
.y
-XXInternalBorder
)/
Vx_mouse_pos
= Fcons (tempx
, Fcons (tempy
, Qnil
));
XSET (tempx
, Lisp_Int
, event
.xbutton
.x_root
);
XSET (tempy
, Lisp_Int
, event
.xbutton
.y_root
);
Vx_mouse_abs_pos
= Fcons (tempx
, Fcons (tempy
, Qnil
));
Vx_mouse_item
= make_number (com_letter
);
= get_keyelt (access_keymap (MouseMap
, com_letter
));
if (event
.type
!= ButtonRelease
)
return call1 (mouse_cmd
, Vx_mouse_pos
);
DEFUN ("x-get-mouse-event", Fx_get_mouse_event
, Sx_get_mouse_event
,
"Get next mouse event out of mouse event buffer (com-letter (x y)).\n\
ARG non-nil means return nil immediately if no pending event;\n\
otherwise, wait for an event.")
register char com_letter
;
register Lisp_Object tempx
;
register Lisp_Object tempy
;
consume_available_input ();
Fsleep_for (make_number (1));
/*** ??? Surely you don't mean to busy wait??? */
event
= *XXm_queue
[XXm_queue_out
];
free (XXm_queue
[XXm_queue_out
]);
XXm_queue_out
= (XXm_queue_out
+ 1) % XMOUSEBUFSIZE
;
com_letter
= 3-(event
.xbutton
.button
& 3);
key_mask
= (event
.xbutton
.state
& 15) << 4;
/* Report meta in 2 bit, not in 8 bit. */
if (event
.type
== ButtonRelease
)
max (0, (event
.xbutton
.x
-XXInternalBorder
)/
max (0, (event
.xbutton
.y
-XXInternalBorder
)/
Vx_mouse_pos
= Fcons (tempx
, Fcons (tempy
, Qnil
));
XSET (tempx
, Lisp_Int
, event
.xbutton
.x_root
);
XSET (tempy
, Lisp_Int
, event
.xbutton
.y_root
);
Vx_mouse_abs_pos
= Fcons (tempx
, Fcons (tempy
, Qnil
));
Vx_mouse_item
= make_number (com_letter
);
return Fcons (com_letter
, Fcons (Vx_mouse_pos
, Qnil
));
DEFUN ("x-store-cut-buffer", Fx_store_cut_buffer
, Sx_store_cut_buffer
,
1, 1, "sSend string to X:",
"Store contents of STRING into the cut buffer of the X window system.")
register Lisp_Object string
;
CHECK_STRING (string
, 1);
XStoreBytes (XXdisplay
, XSTRING (string
)->data
,
/* Clear the selection owner, so that other applications
will use the cut buffer rather than a selection. */
XSetSelectionOwner (XXdisplay
, XA_PRIMARY
, None
, CurrentTime
);
DEFUN ("x-get-cut-buffer", Fx_get_cut_buffer
, Sx_get_cut_buffer
, 0, 0, 0,
"Return contents of cut buffer of the X window system, as a string.")
register Lisp_Object string
;
d
= XFetchBytes (XXdisplay
, &len
);
string
= make_string (d
, len
);
DEFUN ("x-set-border-width", Fx_set_border_width
, Sx_set_border_width
,
"Set width of border to WIDTH, in the X window system.")
register Lisp_Object borderwidth
;
CHECK_NUMBER (borderwidth
, 0);
if (XINT (borderwidth
) < 0)
XSETINT (borderwidth
, 0);
XSetWindowBorderWidth(XXdisplay
, XXwindow
, XINT(borderwidth
));
DEFUN ("x-set-internal-border-width", Fx_set_internal_border_width
,
Sx_set_internal_border_width
, 1, 1, "nInternal border width: ",
"Set width of internal border to WIDTH, in the X window system.")
register Lisp_Object internalborderwidth
;
CHECK_NUMBER (internalborderwidth
, 0);
if (XINT (internalborderwidth
) < 0)
XSETINT (internalborderwidth
, 0);
XXInternalBorder
= XINT(internalborderwidth
);
XSetWindowSize(screen_height
,screen_width
);
DEFUN ("x-rebind-key", Fx_rebind_key
, Sx_rebind_key
, 3, 3, 0,
"Rebind KEYCODE, with shift bits SHIFT-MASK, to new string NEWSTRING.\n\
KEYCODE and SHIFT-MASK should be numbers representing the X keyboard code\n\
and shift mask respectively. NEWSTRING is an arbitrary string of keystrokes.\n\
If SHIFT-MASK is nil, then KEYCODE's key will be bound to NEWSTRING for\n\
all shift combinations.\n\
For values of KEYCODE, see /usr/lib/Xkeymap.txt (remember that the codes\n\
in that file are in octal!)\n")
(keycode
, shift_mask
, newstring
)
register Lisp_Object keycode
;
register Lisp_Object shift_mask
;
register Lisp_Object newstring
;
CHECK_NUMBER (keycode
, 1);
CHECK_NUMBER (shift_mask
, 2);
CHECK_STRING (newstring
, 3);
strsize
= XSTRING (newstring
) ->size
;
rawstring
= (char *) xmalloc (strsize
);
bcopy (XSTRING (newstring
)->data
, rawstring
, strsize
);
rawkey
= ((unsigned) (XINT (keycode
))) & 255;
for (i
= 0; i
<= 15; i
++)
XRebindCode (rawkey
, i
<<11, rawstring
, strsize
);
rawshift
= (((unsigned) (XINT (shift_mask
))) & 15) << 11;
XRebindCode (rawkey
, rawshift
, rawstring
, strsize
);
DEFUN ("x-rebind-keys", Fx_rebind_keys
, Sx_rebind_keys
, 2, 2, 0,
"Rebind KEYCODE to list of strings STRINGS.\n\
STRINGS should be a list of 16 elements, one for each all shift combination.\n\
nil as element means don't change.\n\
See the documentation of x-rebind-key for more information.")
register Lisp_Object keycode
;
register Lisp_Object strings
;
register Lisp_Object item
;
register char *rawstring
;
CHECK_NUMBER (keycode
, 1);
rawkey
= ((unsigned) (XINT (keycode
))) & 255;
for (i
= 0; i
<= 15; strings
= Fcdr (strings
), i
++)
strsize
= XSTRING (item
)->size
;
rawstring
= (char *) xmalloc (strsize
);
bcopy (XSTRING (item
)->data
, rawstring
, strsize
);
XRebindCode (rawkey
, i
<< 11, rawstring
, strsize
);
DEFUN ("x-debug", Fx_debug
, Sx_debug
, 1, 1, 0,
"ARG non-nil means that X errors should generate a coredump.")
register Lisp_Object arg
;
handler
= XExitWithCoreDump
;
extern int XIgnoreError ();
XSetErrorHandler(handler
);
XSetIOErrorHandler(handler
);
kill_buffer_processes (Qnil
);
#endif /* subprocesses */
/* If not dumping, init_display ran before us, so don't override it. */
DEFVAR_LISP ("x-mouse-item", &Vx_mouse_item
,
"Encoded representation of last mouse click, corresponding to\n\
numerical entries in x-mouse-map.");
DEFVAR_LISP ("x-mouse-pos", &Vx_mouse_pos
,
"Current x-y position of mouse by row, column as specified by font.");
DEFVAR_LISP ("x-mouse-abs-pos", &Vx_mouse_abs_pos
,
"Current x-y position of mouse relative to root window.");
defsubr (&Sx_flip_color
);
defsubr (&Scoordinates_in_window_p
);
defsubr (&Sx_mouse_events
);
defsubr (&Sx_proc_mouse_event
);
defsubr (&Sx_get_mouse_event
);
defsubr (&Sx_store_cut_buffer
);
defsubr (&Sx_get_cut_buffer
);
defsubr (&Sx_set_border_width
);
defsubr (&Sx_set_internal_border_width
);
defsubr (&Sx_set_foreground_color
);
defsubr (&Sx_set_background_color
);
defsubr (&Sx_set_border_color
);
defsubr (&Sx_set_cursor_color
);
defsubr (&Sx_set_mouse_color
);
defsubr (&Sx_get_foreground_color
);
defsubr (&Sx_get_background_color
);
defsubr (&Sx_get_border_color
);
defsubr (&Sx_get_cursor_color
);
defsubr (&Sx_get_mouse_color
);
defsubr (&Sx_get_default
);
defsubr (&Sx_rebind_key
);
defsubr (&Sx_rebind_keys
);
#endif /* HAVE_X_WINDOWS */