[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] Changes to emacs/src/xterm.c [emacs-unicode-2]
From: |
Kenichi Handa |
Subject: |
[Emacs-diffs] Changes to emacs/src/xterm.c [emacs-unicode-2] |
Date: |
Mon, 08 Sep 2003 08:49:39 -0400 |
Index: emacs/src/xterm.c
diff -c /dev/null emacs/src/xterm.c:1.804.2.1
*** /dev/null Mon Sep 8 08:49:39 2003
--- emacs/src/xterm.c Mon Sep 8 08:48:17 2003
***************
*** 0 ****
--- 1,10997 ----
+ /* X Communication module for terminals which understand the X protocol.
+ Copyright (C) 1989, 93, 94, 95, 96, 97, 98, 1999, 2000, 01, 02, 2003
+ 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 2, 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, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+ /* New display code by Gerd Moellmann <address@hidden>. */
+ /* Xt features made by Fred Pierresteguy. */
+
+ #include <config.h>
+
+ /* On 4.3 these lose if they come after xterm.h. */
+ /* Putting these at the beginning seems to be standard for other .c files. */
+ #include <signal.h>
+
+ #include <stdio.h>
+
+ #ifdef HAVE_X_WINDOWS
+
+ #include "lisp.h"
+ #include "blockinput.h"
+
+ /* Need syssignal.h for various externs and definitions that may be required
+ by some configurations for calls to signal later in this source file. */
+ #include "syssignal.h"
+
+ /* This may include sys/types.h, and that somehow loses
+ if this is not done before the other system files. */
+ #include "xterm.h"
+ #include <X11/cursorfont.h>
+
+ /* Load sys/types.h if not already loaded.
+ In some systems loading it twice is suicidal. */
+ #ifndef makedev
+ #include <sys/types.h>
+ #endif /* makedev */
+
+ #ifdef BSD_SYSTEM
+ #include <sys/ioctl.h>
+ #endif /* ! defined (BSD_SYSTEM) */
+
+ #include "systty.h"
+ #include "systime.h"
+
+ #ifndef INCLUDED_FCNTL
+ #include <fcntl.h>
+ #endif
+ #include <ctype.h>
+ #include <errno.h>
+ #include <setjmp.h>
+ #include <sys/stat.h>
+ /* Caused redefinition of DBL_DIG on Netbsd; seems not to be needed. */
+ /* #include <sys/param.h> */
+
+ #include "charset.h"
+ #include "character.h"
+ #include "coding.h"
+ #include "ccl.h"
+ #include "frame.h"
+ #include "dispextern.h"
+ #include "fontset.h"
+ #include "termhooks.h"
+ #include "termopts.h"
+ #include "termchar.h"
+ #include "gnu.h"
+ #include "disptab.h"
+ #include "buffer.h"
+ #include "window.h"
+ #include "keyboard.h"
+ #include "intervals.h"
+ #include "process.h"
+ #include "atimer.h"
+ #include "keymap.h"
+
+ #ifdef USE_X_TOOLKIT
+ #include <X11/Shell.h>
+ #endif
+
+ #ifdef HAVE_SYS_TIME_H
+ #include <sys/time.h>
+ #endif
+ #ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+ #endif
+
+ #ifdef USE_GTK
+ #include "gtkutil.h"
+ #endif
+
+ #ifdef USE_LUCID
+ extern int xlwmenu_window_p P_ ((Widget w, Window window));
+ extern void xlwmenu_redisplay P_ ((Widget));
+ #endif
+
+ #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
+
+ extern void free_frame_menubar P_ ((struct frame *));
+ extern struct frame *x_menubar_window_to_frame P_ ((struct x_display_info *,
+ int));
+ #endif
+
+ #ifdef USE_X_TOOLKIT
+ #if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
+ #define HACK_EDITRES
+ extern void _XEditResCheckMessages ();
+ #endif /* not NO_EDITRES */
+
+ /* Include toolkit specific headers for the scroll bar widget. */
+
+ #ifdef USE_TOOLKIT_SCROLL_BARS
+ #if defined USE_MOTIF
+ #include <Xm/Xm.h> /* for LESSTIF_VERSION */
+ #include <Xm/ScrollBar.h>
+ #else /* !USE_MOTIF i.e. use Xaw */
+
+ #ifdef HAVE_XAW3D
+ #include <X11/Xaw3d/Simple.h>
+ #include <X11/Xaw3d/Scrollbar.h>
+ #define ARROW_SCROLLBAR
+ #include <X11/Xaw3d/ScrollbarP.h>
+ #else /* !HAVE_XAW3D */
+ #include <X11/Xaw/Simple.h>
+ #include <X11/Xaw/Scrollbar.h>
+ #endif /* !HAVE_XAW3D */
+ #ifndef XtNpickTop
+ #define XtNpickTop "pickTop"
+ #endif /* !XtNpickTop */
+ #endif /* !USE_MOTIF */
+ #endif /* USE_TOOLKIT_SCROLL_BARS */
+
+ #endif /* USE_X_TOOLKIT */
+
+ #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
+ #define x_any_window_to_frame x_window_to_frame
+ #define x_top_window_to_frame x_window_to_frame
+ #endif
+
+ #ifdef USE_X_TOOLKIT
+ #include "widget.h"
+ #ifndef XtNinitialState
+ #define XtNinitialState "initialState"
+ #endif
+ #endif
+
+ #define abs(x) ((x) < 0 ? -(x) : (x))
+
+ /* Default to using XIM if available. */
+ #ifdef USE_XIM
+ int use_xim = 1;
+ #else
+ int use_xim = 0; /* configure --without-xim */
+ #endif
+
+
+
+ /* Non-nil means Emacs uses toolkit scroll bars. */
+
+ Lisp_Object Vx_toolkit_scroll_bars;
+
+ /* Non-zero means that a HELP_EVENT has been generated since Emacs
+ start. */
+
+ static int any_help_event_p;
+
+ /* Last window where we saw the mouse. Used by mouse-autoselect-window. */
+ static Lisp_Object last_window;
+
+ /* Non-zero means make use of UNDERLINE_POSITION font properties. */
+
+ int x_use_underline_position_properties;
+
+ /* This is a chain of structures for all the X displays currently in
+ use. */
+
+ struct x_display_info *x_display_list;
+
+ /* This is a list of cons cells, each of the form (NAME
+ . FONT-LIST-CACHE), one for each element of x_display_list and in
+ the same order. NAME is the name of the frame. FONT-LIST-CACHE
+ records previous values returned by x-list-fonts. */
+
+ Lisp_Object x_display_name_list;
+
+ /* Frame being updated by update_frame. This is declared in term.c.
+ This is set by update_begin and looked at by all the XT functions.
+ It is zero while not inside an update. In that case, the XT
+ functions assume that `selected_frame' is the frame to apply to. */
+
+ extern struct frame *updating_frame;
+
+ /* This is a frame waiting to be auto-raised, within XTread_socket. */
+
+ struct frame *pending_autoraise_frame;
+
+ #ifdef USE_X_TOOLKIT
+ /* The application context for Xt use. */
+ XtAppContext Xt_app_con;
+ static String Xt_default_resources[] = {0};
+ #endif /* USE_X_TOOLKIT */
+
+ /* Non-zero means user is interacting with a toolkit scroll bar. */
+
+ static int toolkit_scroll_bar_interaction;
+
+ /* Mouse movement.
+
+ Formerly, we used PointerMotionHintMask (in standard_event_mask)
+ so that we would have to call XQueryPointer after each MotionNotify
+ event to ask for another such event. However, this made mouse tracking
+ slow, and there was a bug that made it eventually stop.
+
+ Simply asking for MotionNotify all the time seems to work better.
+
+ In order to avoid asking for motion events and then throwing most
+ of them away or busy-polling the server for mouse positions, we ask
+ the server for pointer motion hints. This means that we get only
+ one event per group of mouse movements. "Groups" are delimited by
+ other kinds of events (focus changes and button clicks, for
+ example), or by XQueryPointer calls; when one of these happens, we
+ get another MotionNotify event the next time the mouse moves. This
+ is at least as efficient as getting motion events when mouse
+ tracking is on, and I suspect only negligibly worse when tracking
+ is off. */
+
+ /* Where the mouse was last time we reported a mouse event. */
+
+ static XRectangle last_mouse_glyph;
+ static Lisp_Object last_mouse_press_frame;
+
+ /* The scroll bar in which the last X motion event occurred.
+
+ If the last X motion event occurred in a scroll bar, we set this so
+ XTmouse_position can know whether to report a scroll bar motion or
+ an ordinary motion.
+
+ If the last X motion event didn't occur in a scroll bar, we set
+ this to Qnil, to tell XTmouse_position to return an ordinary motion
+ event. */
+
+ static Lisp_Object last_mouse_scroll_bar;
+
+ /* This is a hack. We would really prefer that XTmouse_position would
+ return the time associated with the position it returns, but there
+ doesn't seem to be any way to wrest the time-stamp from the server
+ along with the position query. So, we just keep track of the time
+ of the last movement we received, and return that in hopes that
+ it's somewhat accurate. */
+
+ static Time last_mouse_movement_time;
+
+ /* Incremented by XTread_socket whenever it really tries to read
+ events. */
+
+ #ifdef __STDC__
+ static int volatile input_signal_count;
+ #else
+ static int input_signal_count;
+ #endif
+
+ /* Used locally within XTread_socket. */
+
+ static int x_noop_count;
+
+ /* Initial values of argv and argc. */
+
+ extern char **initial_argv;
+ extern int initial_argc;
+
+ extern Lisp_Object Vcommand_line_args, Vsystem_name;
+
+ /* Tells if a window manager is present or not. */
+
+ extern Lisp_Object Vx_no_window_manager;
+
+ extern Lisp_Object Qface, Qmouse_face, Qeql;
+
+ extern int errno;
+
+ /* A mask of extra modifier bits to put into every keyboard char. */
+
+ extern EMACS_INT extra_keyboard_modifiers;
+
+ /* The keysyms to use for the various modifiers. */
+
+ Lisp_Object Vx_alt_keysym, Vx_hyper_keysym, Vx_meta_keysym, Vx_super_keysym;
+ Lisp_Object Vx_keysym_table;
+ static Lisp_Object Qalt, Qhyper, Qmeta, Qsuper, Qmodifier_value;
+
+ static Lisp_Object Qvendor_specific_keysyms;
+ static Lisp_Object Qlatin_1;
+
+ extern XrmDatabase x_load_resources P_ ((Display *, char *, char *, char *));
+
+
+ static int x_alloc_nearest_color_1 P_ ((Display *, Colormap, XColor *));
+ static void x_set_window_size_1 P_ ((struct frame *, int, int, int));
+ static const XColor *x_color_cells P_ ((Display *, int *));
+ static void x_update_window_end P_ ((struct window *, int, int));
+ void x_delete_display P_ ((struct x_display_info *));
+ static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
+ unsigned));
+ static int x_io_error_quitter P_ ((Display *));
+ int x_catch_errors P_ ((Display *));
+ void x_uncatch_errors P_ ((Display *, int));
+ void x_lower_frame P_ ((struct frame *));
+ void x_scroll_bar_clear P_ ((struct frame *));
+ int x_had_errors_p P_ ((Display *));
+ void x_wm_set_size_hint P_ ((struct frame *, long, int));
+ void x_raise_frame P_ ((struct frame *));
+ void x_set_window_size P_ ((struct frame *, int, int, int));
+ void x_wm_set_window_state P_ ((struct frame *, int));
+ void x_wm_set_icon_pixmap P_ ((struct frame *, int));
+ void x_initialize P_ ((void));
+ static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
+ static int x_compute_min_glyph_bounds P_ ((struct frame *));
+ static void x_update_end P_ ((struct frame *));
+ static void XTframe_up_to_date P_ ((struct frame *));
+ static void XTset_terminal_modes P_ ((void));
+ static void XTreset_terminal_modes P_ ((void));
+ static void x_clear_frame P_ ((void));
+ static void frame_highlight P_ ((struct frame *));
+ static void frame_unhighlight P_ ((struct frame *));
+ static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
+ static int x_focus_changed P_ ((int,
+ int,
+ struct x_display_info *,
+ struct frame *,
+ struct input_event *,
+ int));
+ static int x_detect_focus_change P_ ((struct x_display_info *,
+ XEvent *,
+ struct input_event *,
+ int));
+ static void XTframe_rehighlight P_ ((struct frame *));
+ static void x_frame_rehighlight P_ ((struct x_display_info *));
+ static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
+ static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int,
+ enum text_cursor_kinds));
+
+ static void x_clip_to_row P_ ((struct window *, struct glyph_row *, GC));
+ static void x_flush P_ ((struct frame *f));
+ static void x_update_begin P_ ((struct frame *));
+ static void x_update_window_begin P_ ((struct window *));
+ static void x_after_update_window_line P_ ((struct glyph_row *));
+ static struct scroll_bar *x_window_to_scroll_bar P_ ((Window));
+ static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *,
+ enum scroll_bar_part *,
+ Lisp_Object *, Lisp_Object *,
+ unsigned long *));
+ static void x_check_fullscreen P_ ((struct frame *));
+ static void x_check_fullscreen_move P_ ((struct frame *));
+ static int handle_one_xevent P_ ((struct x_display_info *,
+ XEvent *,
+ struct input_event **,
+ int *,
+ int *));
+
+
+ /* Flush display of frame F, or of all frames if F is null. */
+
+ static void
+ x_flush (f)
+ struct frame *f;
+ {
+ BLOCK_INPUT;
+ if (f == NULL)
+ {
+ Lisp_Object rest, frame;
+ FOR_EACH_FRAME (rest, frame)
+ x_flush (XFRAME (frame));
+ }
+ else if (FRAME_X_P (f))
+ XFlush (FRAME_X_DISPLAY (f));
+ UNBLOCK_INPUT;
+ }
+
+
+ /* Remove calls to XFlush by defining XFlush to an empty replacement.
+ Calls to XFlush should be unnecessary because the X output buffer
+ is flushed automatically as needed by calls to XPending,
+ XNextEvent, or XWindowEvent according to the XFlush man page.
+ XTread_socket calls XPending. Removing XFlush improves
+ performance. */
+
+ #define XFlush(DISPLAY) (void) 0
+
+
+ /***********************************************************************
+ Debugging
+ ***********************************************************************/
+
+ #if 0
+
+ /* This is a function useful for recording debugging information about
+ the sequence of occurrences in this file. */
+
+ struct record
+ {
+ char *locus;
+ int type;
+ };
+
+ struct record event_record[100];
+
+ int event_record_index;
+
+ record_event (locus, type)
+ char *locus;
+ int type;
+ {
+ if (event_record_index == sizeof (event_record) / sizeof (struct record))
+ event_record_index = 0;
+
+ event_record[event_record_index].locus = locus;
+ event_record[event_record_index].type = type;
+ event_record_index++;
+ }
+
+ #endif /* 0 */
+
+
+
+ /* Return the struct x_display_info corresponding to DPY. */
+
+ struct x_display_info *
+ x_display_info_for_display (dpy)
+ Display *dpy;
+ {
+ struct x_display_info *dpyinfo;
+
+ for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
+ if (dpyinfo->display == dpy)
+ return dpyinfo;
+
+ return 0;
+ }
+
+
+
+ /***********************************************************************
+ Starting and ending an update
+ ***********************************************************************/
+
+ /* Start an update of frame F. This function is installed as a hook
+ for update_begin, i.e. it is called when update_begin is called.
+ This function is called prior to calls to x_update_window_begin for
+ each window being updated. Currently, there is nothing to do here
+ because all interesting stuff is done on a window basis. */
+
+ static void
+ x_update_begin (f)
+ struct frame *f;
+ {
+ /* Nothing to do. */
+ }
+
+
+ /* Start update of window W. Set the global variable updated_window
+ to the window being updated and set output_cursor to the cursor
+ position of W. */
+
+ static void
+ x_update_window_begin (w)
+ struct window *w;
+ {
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
+
+ updated_window = w;
+ set_output_cursor (&w->cursor);
+
+ BLOCK_INPUT;
+
+ if (f == display_info->mouse_face_mouse_frame)
+ {
+ /* Don't do highlighting for mouse motion during the update. */
+ display_info->mouse_face_defer = 1;
+
+ /* If F needs to be redrawn, simply forget about any prior mouse
+ highlighting. */
+ if (FRAME_GARBAGED_P (f))
+ display_info->mouse_face_window = Qnil;
+
+ #if 0 /* Rows in a current matrix containing glyphs in mouse-face have
+ their mouse_face_p flag set, which means that they are always
+ unequal to rows in a desired matrix which never have that
+ flag set. So, rows containing mouse-face glyphs are never
+ scrolled, and we don't have to switch the mouse highlight off
+ here to prevent it from being scrolled. */
+
+ /* Can we tell that this update does not affect the window
+ where the mouse highlight is? If so, no need to turn off.
+ Likewise, don't do anything if the frame is garbaged;
+ in that case, the frame's current matrix that we would use
+ is all wrong, and we will redisplay that line anyway. */
+ if (!NILP (display_info->mouse_face_window)
+ && w == XWINDOW (display_info->mouse_face_window))
+ {
+ int i;
+
+ for (i = 0; i < w->desired_matrix->nrows; ++i)
+ if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
+ break;
+
+ if (i < w->desired_matrix->nrows)
+ clear_mouse_face (display_info);
+ }
+ #endif /* 0 */
+ }
+
+ UNBLOCK_INPUT;
+ }
+
+
+ /* Draw a vertical window border from (x,y0) to (x,y1) */
+
+ static void
+ x_draw_vertical_window_border (w, x, y0, y1)
+ struct window *w;
+ int x, y0, y1;
+ {
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+
+ XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ f->output_data.x->normal_gc, x, y0, x, y1);
+ }
+
+ /* End update of window W (which is equal to updated_window).
+
+ Draw vertical borders between horizontally adjacent windows, and
+ display W's cursor if CURSOR_ON_P is non-zero.
+
+ MOUSE_FACE_OVERWRITTEN_P non-zero means that some row containing
+ glyphs in mouse-face were overwritten. In that case we have to
+ make sure that the mouse-highlight is properly redrawn.
+
+ W may be a menu bar pseudo-window in case we don't have X toolkit
+ support. Such windows don't have a cursor, so don't display it
+ here. */
+
+ static void
+ x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p)
+ struct window *w;
+ int cursor_on_p, mouse_face_overwritten_p;
+ {
+ struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
+
+ if (!w->pseudo_window_p)
+ {
+ BLOCK_INPUT;
+
+ if (cursor_on_p)
+ display_and_set_cursor (w, 1, output_cursor.hpos,
+ output_cursor.vpos,
+ output_cursor.x, output_cursor.y);
+
+ x_draw_vertical_border (w);
+ UNBLOCK_INPUT;
+ }
+
+ /* If a row with mouse-face was overwritten, arrange for
+ XTframe_up_to_date to redisplay the mouse highlight. */
+ if (mouse_face_overwritten_p)
+ {
+ dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
+ dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
+ dpyinfo->mouse_face_window = Qnil;
+ }
+
+ updated_window = NULL;
+ }
+
+
+ /* End update of frame F. This function is installed as a hook in
+ update_end. */
+
+ static void
+ x_update_end (f)
+ struct frame *f;
+ {
+ /* Mouse highlight may be displayed again. */
+ FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
+
+ #ifndef XFlush
+ BLOCK_INPUT;
+ XFlush (FRAME_X_DISPLAY (f));
+ UNBLOCK_INPUT;
+ #endif
+ }
+
+
+ /* This function is called from various places in xdisp.c whenever a
+ complete update has been performed. The global variable
+ updated_window is not available here. */
+
+ static void
+ XTframe_up_to_date (f)
+ struct frame *f;
+ {
+ if (FRAME_X_P (f))
+ {
+ struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+
+ if (dpyinfo->mouse_face_deferred_gc
+ || f == dpyinfo->mouse_face_mouse_frame)
+ {
+ BLOCK_INPUT;
+ if (dpyinfo->mouse_face_mouse_frame)
+ note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
+ dpyinfo->mouse_face_mouse_x,
+ dpyinfo->mouse_face_mouse_y);
+ dpyinfo->mouse_face_deferred_gc = 0;
+ UNBLOCK_INPUT;
+ }
+ }
+ }
+
+
+ /* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
+ arrow bitmaps, or clear the fringes if no bitmaps are required
+ before DESIRED_ROW is made current. The window being updated is
+ found in updated_window. This function It is called from
+ update_window_line only if it is known that there are differences
+ between bitmaps to be drawn between current row and DESIRED_ROW. */
+
+ static void
+ x_after_update_window_line (desired_row)
+ struct glyph_row *desired_row;
+ {
+ struct window *w = updated_window;
+ struct frame *f;
+ int width, height;
+
+ xassert (w);
+
+ if (!desired_row->mode_line_p && !w->pseudo_window_p)
+ {
+ BLOCK_INPUT;
+ draw_row_fringe_bitmaps (w, desired_row);
+ UNBLOCK_INPUT;
+ }
+
+ /* When a window has disappeared, make sure that no rest of
+ full-width rows stays visible in the internal border. Could
+ check here if updated_window is the leftmost/rightmost window,
+ but I guess it's not worth doing since vertically split windows
+ are almost never used, internal border is rarely set, and the
+ overhead is very small. */
+ if (windows_or_buffers_changed
+ && desired_row->full_width_p
+ && (f = XFRAME (w->frame),
+ width = FRAME_INTERNAL_BORDER_WIDTH (f),
+ width != 0)
+ && (height = desired_row->visible_height,
+ height > 0))
+ {
+ int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
+
+ /* Internal border is drawn below the tool bar. */
+ if (WINDOWP (f->tool_bar_window)
+ && w == XWINDOW (f->tool_bar_window))
+ y -= width;
+
+ BLOCK_INPUT;
+ x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ 0, y, width, height, False);
+ x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ FRAME_PIXEL_WIDTH (f) - width,
+ y, width, height, False);
+ UNBLOCK_INPUT;
+ }
+ }
+
+ static void
+ x_draw_fringe_bitmap (w, row, p)
+ struct window *w;
+ struct glyph_row *row;
+ struct draw_fringe_bitmap_params *p;
+ {
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ Display *display = FRAME_X_DISPLAY (f);
+ Window window = FRAME_X_WINDOW (f);
+ GC gc = f->output_data.x->normal_gc;
+ struct face *face = p->face;
+
+ /* Must clip because of partially visible lines. */
+ x_clip_to_row (w, row, gc);
+
+ if (p->bx >= 0)
+ {
+ /* In case the same realized face is used for fringes and
+ for something displayed in the text (e.g. face `region' on
+ mono-displays, the fill style may have been changed to
+ FillSolid in x_draw_glyph_string_background. */
+ if (face->stipple)
+ XSetFillStyle (display, face->gc, FillOpaqueStippled);
+ else
+ XSetForeground (display, face->gc, face->background);
+
+ XFillRectangle (display, window, face->gc,
+ p->bx, p->by, p->nx, p->ny);
+
+ if (!face->stipple)
+ XSetForeground (display, face->gc, face->foreground);
+ }
+
+ if (p->which != NO_FRINGE_BITMAP)
+ {
+ unsigned char *bits = fringe_bitmaps[p->which].bits + p->dh;
+ Pixmap pixmap;
+ int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
+
+ /* Draw the bitmap. I believe these small pixmaps can be cached
+ by the server. */
+ pixmap = XCreatePixmapFromBitmapData (display, window, bits, p->wd,
p->h,
+ face->foreground,
+ face->background, depth);
+ XCopyArea (display, pixmap, window, gc, 0, 0,
+ p->wd, p->h, p->x, p->y);
+ XFreePixmap (display, pixmap);
+ }
+
+ XSetClipMask (display, gc, None);
+ }
+
+
+
+ /* This is called 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 void
+ 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 void
+ XTreset_terminal_modes ()
+ {
+ }
+
+
+
+ /***********************************************************************
+ Display Iterator
+ ***********************************************************************/
+
+ /* Function prototypes of this page. */
+
+ static int x_encode_char P_ ((int, XChar2b *, struct font_info *,
+ struct charset *, int *));
+
+
+ /* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
+ is not contained in the font. */
+
+ static XCharStruct *
+ x_per_char_metric (font, char2b, font_type)
+ XFontStruct *font;
+ XChar2b *char2b;
+ int font_type; /* unused on X */
+ {
+ /* The result metric information. */
+ XCharStruct *pcm = NULL;
+
+ xassert (font && char2b);
+
+ if (font->per_char != NULL)
+ {
+ if (font->min_byte1 == 0 && font->max_byte1 == 0)
+ {
+ /* min_char_or_byte2 specifies the linear character index
+ corresponding to the first element of the per_char array,
+ max_char_or_byte2 is the index of the last character. A
+ character with non-zero CHAR2B->byte1 is not in the font.
+ A character with byte2 less than min_char_or_byte2 or
+ greater max_char_or_byte2 is not in the font. */
+ if (char2b->byte1 == 0
+ && char2b->byte2 >= font->min_char_or_byte2
+ && char2b->byte2 <= font->max_char_or_byte2)
+ pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
+ }
+ else
+ {
+ /* If either min_byte1 or max_byte1 are nonzero, both
+ min_char_or_byte2 and max_char_or_byte2 are less than
+ 256, and the 2-byte character index values corresponding
+ to the per_char array element N (counting from 0) are:
+
+ byte1 = N/D + min_byte1
+ byte2 = N\D + min_char_or_byte2
+
+ where:
+
+ D = max_char_or_byte2 - min_char_or_byte2 + 1
+ / = integer division
+ \ = integer modulus */
+ if (char2b->byte1 >= font->min_byte1
+ && char2b->byte1 <= font->max_byte1
+ && char2b->byte2 >= font->min_char_or_byte2
+ && char2b->byte2 <= font->max_char_or_byte2)
+ {
+ pcm = (font->per_char
+ + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
+ * (char2b->byte1 - font->min_byte1))
+ + (char2b->byte2 - font->min_char_or_byte2));
+ }
+ }
+ }
+ else
+ {
+ /* If the per_char pointer is null, all glyphs between the first
+ and last character indexes inclusive have the same
+ information, as given by both min_bounds and max_bounds. */
+ if (char2b->byte2 >= font->min_char_or_byte2
+ && char2b->byte2 <= font->max_char_or_byte2)
+ pcm = &font->max_bounds;
+ }
+
+ return ((pcm == NULL
+ || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
+ ? NULL : pcm);
+ }
+
+
+ /* Encode CHAR2B using encoding information from FONT_INFO. CHAR2B is
+ the two-byte form of C. Encoding is returned in *CHAR2B. */
+
+ static int
+ x_encode_char (c, char2b, font_info, charset, two_byte_p)
+ int c;
+ XChar2b *char2b;
+ struct font_info *font_info;
+ struct charset *charset;
+ int *two_byte_p;
+ {
+ XFontStruct *font = font_info->font;
+
+ /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
+ This may be either a program in a special encoder language or a
+ fixed encoding. */
+ if (font_info->font_encoder)
+ {
+ /* It's a program. */
+ struct ccl_program *ccl = font_info->font_encoder;
+
+ if (CHARSET_DIMENSION (charset) == 1)
+ {
+ ccl->reg[0] = CHARSET_ID (charset);
+ ccl->reg[1] = char2b->byte2;
+ ccl->reg[2] = -1;
+ }
+ else
+ {
+ ccl->reg[0] = CHARSET_ID (charset);
+ ccl->reg[1] = char2b->byte1;
+ ccl->reg[2] = char2b->byte2;
+ }
+
+ ccl_driver (ccl, NULL, NULL, 0, 0, Qnil);
+
+ /* We assume that MSBs are appropriately set/reset by CCL
+ program. */
+ if (font->max_byte1 == 0) /* 1-byte font */
+ STORE_XCHAR2B (char2b, 0, ccl->reg[1]);
+ else
+ STORE_XCHAR2B (char2b, ccl->reg[1], ccl->reg[2]);
+ }
+ else if (font_info->encoding_type)
+ {
+ /* Fixed encoding scheme. See fontset.h for the meaning of the
+ encoding numbers. */
+ unsigned char enc = font_info->encoding_type;
+
+ if ((enc == 1 || enc == 2)
+ && CHARSET_DIMENSION (charset) == 2)
+ char2b->byte1 |= 0x80;
+
+ if (enc == 1 || enc == 3)
+ char2b->byte2 |= 0x80;
+ }
+
+ if (two_byte_p)
+ *two_byte_p = ((XFontStruct *) (font_info->font))->max_byte1 > 0;
+
+ return FONT_TYPE_UNKNOWN;
+ }
+
+
+
+ /***********************************************************************
+ Glyph display
+ ***********************************************************************/
+
+
+
+ static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
+ static void x_set_glyph_string_gc P_ ((struct glyph_string *));
+ static void x_draw_glyph_string_background P_ ((struct glyph_string *,
+ int));
+ static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
+ static void x_draw_composite_glyph_string_foreground P_ ((struct glyph_string
*));
+ static void x_draw_glyph_string_box P_ ((struct glyph_string *));
+ static void x_draw_glyph_string P_ ((struct glyph_string *));
+ static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
+ static void x_set_cursor_gc P_ ((struct glyph_string *));
+ static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
+ static void x_set_mouse_face_gc P_ ((struct glyph_string *));
+ static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
+ unsigned long *, double, int));
+ static void x_setup_relief_color P_ ((struct frame *, struct relief *,
+ double, int, unsigned long));
+ static void x_setup_relief_colors P_ ((struct glyph_string *));
+ static void x_draw_image_glyph_string P_ ((struct glyph_string *));
+ static void x_draw_image_relief P_ ((struct glyph_string *));
+ static void x_draw_image_foreground P_ ((struct glyph_string *));
+ static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
+ static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
+ int, int, int));
+ static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
+ int, int, int, int, XRectangle *));
+ static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
+ int, int, int, XRectangle *));
+
+ #if GLYPH_DEBUG
+ static void x_check_font P_ ((struct frame *, XFontStruct *));
+ #endif
+
+
+ /* Set S->gc to a suitable GC for drawing glyph string S in cursor
+ face. */
+
+ static void
+ x_set_cursor_gc (s)
+ struct glyph_string *s;
+ {
+ if (s->font == FRAME_FONT (s->f)
+ && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
+ && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
+ && !s->cmp)
+ s->gc = s->f->output_data.x->cursor_gc;
+ else
+ {
+ /* Cursor on non-default face: must merge. */
+ XGCValues xgcv;
+ unsigned long mask;
+
+ xgcv.background = s->f->output_data.x->cursor_pixel;
+ xgcv.foreground = s->face->background;
+
+ /* If the glyph would be invisible, try a different foreground. */
+ if (xgcv.foreground == xgcv.background)
+ xgcv.foreground = s->face->foreground;
+ if (xgcv.foreground == xgcv.background)
+ xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
+ if (xgcv.foreground == xgcv.background)
+ xgcv.foreground = s->face->foreground;
+
+ /* Make sure the cursor is distinct from text in this face. */
+ if (xgcv.background == s->face->background
+ && xgcv.foreground == s->face->foreground)
+ {
+ xgcv.background = s->face->foreground;
+ xgcv.foreground = s->face->background;
+ }
+
+ IF_DEBUG (x_check_font (s->f, s->font));
+ xgcv.font = s->font->fid;
+ xgcv.graphics_exposures = False;
+ mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
+
+ if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
+ XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
+ mask, &xgcv);
+ else
+ FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
+ = XCreateGC (s->display, s->window, mask, &xgcv);
+
+ s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
+ }
+ }
+
+
+ /* Set up S->gc of glyph string S for drawing text in mouse face. */
+
+ static void
+ x_set_mouse_face_gc (s)
+ struct glyph_string *s;
+ {
+ int face_id;
+ struct face *face;
+
+ /* What face has to be used last for the mouse face? */
+ face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
+ face = FACE_FROM_ID (s->f, face_id);
+ if (face == NULL)
+ face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
+
+ if (s->first_glyph->type == CHAR_GLYPH)
+ face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
+ else
+ face_id = FACE_FOR_CHAR (s->f, face, 0);
+ s->face = FACE_FROM_ID (s->f, face_id);
+ PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
+
+ /* If font in this face is same as S->font, use it. */
+ if (s->font == s->face->font)
+ s->gc = s->face->gc;
+ else
+ {
+ /* Otherwise construct scratch_cursor_gc with values from FACE
+ but font FONT. */
+ XGCValues xgcv;
+ unsigned long mask;
+
+ xgcv.background = s->face->background;
+ xgcv.foreground = s->face->foreground;
+ IF_DEBUG (x_check_font (s->f, s->font));
+ xgcv.font = s->font->fid;
+ xgcv.graphics_exposures = False;
+ mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
+
+ if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
+ XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
+ mask, &xgcv);
+ else
+ FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
+ = XCreateGC (s->display, s->window, mask, &xgcv);
+
+ s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
+ }
+
+ xassert (s->gc != 0);
+ }
+
+
+ /* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
+ Faces to use in the mode line have already been computed when the
+ matrix was built, so there isn't much to do, here. */
+
+ static INLINE void
+ x_set_mode_line_face_gc (s)
+ struct glyph_string *s;
+ {
+ s->gc = s->face->gc;
+ }
+
+
+ /* Set S->gc of glyph string S for drawing that glyph string. Set
+ S->stippled_p to a non-zero value if the face of S has a stipple
+ pattern. */
+
+ static INLINE void
+ x_set_glyph_string_gc (s)
+ struct glyph_string *s;
+ {
+ PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
+
+ if (s->hl == DRAW_NORMAL_TEXT)
+ {
+ s->gc = s->face->gc;
+ s->stippled_p = s->face->stipple != 0;
+ }
+ else if (s->hl == DRAW_INVERSE_VIDEO)
+ {
+ x_set_mode_line_face_gc (s);
+ s->stippled_p = s->face->stipple != 0;
+ }
+ else if (s->hl == DRAW_CURSOR)
+ {
+ x_set_cursor_gc (s);
+ s->stippled_p = 0;
+ }
+ else if (s->hl == DRAW_MOUSE_FACE)
+ {
+ x_set_mouse_face_gc (s);
+ s->stippled_p = s->face->stipple != 0;
+ }
+ else if (s->hl == DRAW_IMAGE_RAISED
+ || s->hl == DRAW_IMAGE_SUNKEN)
+ {
+ s->gc = s->face->gc;
+ s->stippled_p = s->face->stipple != 0;
+ }
+ else
+ {
+ s->gc = s->face->gc;
+ s->stippled_p = s->face->stipple != 0;
+ }
+
+ /* GC must have been set. */
+ xassert (s->gc != 0);
+ }
+
+
+ /* Set clipping for output of glyph string S. S may be part of a mode
+ line or menu if we don't have X toolkit support. */
+
+ static INLINE void
+ x_set_glyph_string_clipping (s)
+ struct glyph_string *s;
+ {
+ XRectangle r;
+ get_glyph_string_clip_rect (s, &r);
+ XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
+ }
+
+
+ /* RIF:
+ Compute left and right overhang of glyph string S. If S is a glyph
+ string for a composition, assume overhangs don't exist. */
+
+ static void
+ x_compute_glyph_string_overhangs (s)
+ struct glyph_string *s;
+ {
+ if (s->cmp == NULL
+ && s->first_glyph->type == CHAR_GLYPH)
+ {
+ XCharStruct cs;
+ int direction, font_ascent, font_descent;
+ XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
+ &font_ascent, &font_descent, &cs);
+ s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
+ s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
+ }
+ }
+
+
+ /* Fill rectangle X, Y, W, H with background color of glyph string S. */
+
+ static INLINE void
+ x_clear_glyph_string_rect (s, x, y, w, h)
+ struct glyph_string *s;
+ int x, y, w, h;
+ {
+ XGCValues xgcv;
+ XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
+ XSetForeground (s->display, s->gc, xgcv.background);
+ XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
+ XSetForeground (s->display, s->gc, xgcv.foreground);
+ }
+
+
+ /* Draw the background of glyph_string S. If S->background_filled_p
+ is non-zero don't draw it. FORCE_P non-zero means draw the
+ background even if it wouldn't be drawn normally. This is used
+ when a string preceding S draws into the background of S, or S
+ contains the first component of a composition. */
+
+ static void
+ x_draw_glyph_string_background (s, force_p)
+ struct glyph_string *s;
+ int force_p;
+ {
+ /* Nothing to do if background has already been drawn or if it
+ shouldn't be drawn in the first place. */
+ if (!s->background_filled_p)
+ {
+ int box_line_width = max (s->face->box_line_width, 0);
+
+ if (s->stippled_p)
+ {
+ /* Fill background with a stipple pattern. */
+ XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
+ XFillRectangle (s->display, s->window, s->gc, s->x,
+ s->y + box_line_width,
+ s->background_width,
+ s->height - 2 * box_line_width);
+ XSetFillStyle (s->display, s->gc, FillSolid);
+ s->background_filled_p = 1;
+ }
+ else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
+ || s->font_not_found_p
+ || s->extends_to_end_of_line_p
+ || force_p)
+ {
+ x_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
+ s->background_width,
+ s->height - 2 * box_line_width);
+ s->background_filled_p = 1;
+ }
+ }
+ }
+
+
+ /* Draw the foreground of glyph string S. */
+
+ static void
+ x_draw_glyph_string_foreground (s)
+ struct glyph_string *s;
+ {
+ int i, x;
+
+ /* If first glyph of S has a left box line, start drawing the text
+ of S to the right of that box line. */
+ if (s->face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p)
+ x = s->x + abs (s->face->box_line_width);
+ else
+ x = s->x;
+
+ /* Draw characters of S as rectangles if S's font could not be
+ loaded. */
+ if (s->font_not_found_p)
+ {
+ for (i = 0; i < s->nchars; ++i)
+ {
+ struct glyph *g = s->first_glyph + i;
+ XDrawRectangle (s->display, s->window,
+ s->gc, x, s->y, g->pixel_width - 1,
+ s->height - 1);
+ x += g->pixel_width;
+ }
+ }
+ else
+ {
+ char *char1b = (char *) s->char2b;
+ int boff = s->font_info->baseline_offset;
+
+ if (s->font_info->vertical_centering)
+ boff = VCENTER_BASELINE_OFFSET (s->font, s->f) - boff;
+
+ /* If we can use 8-bit functions, condense S->char2b. */
+ if (!s->two_byte_p)
+ for (i = 0; i < s->nchars; ++i)
+ char1b[i] = s->char2b[i].byte2;
+
+ /* Draw text with XDrawString if background has already been
+ filled. Otherwise, use XDrawImageString. (Note that
+ XDrawImageString is usually faster than XDrawString.) Always
+ use XDrawImageString when drawing the cursor so that there is
+ no chance that characters under a box cursor are invisible. */
+ if (s->for_overlaps_p
+ || (s->background_filled_p && s->hl != DRAW_CURSOR))
+ {
+ /* Draw characters with 16-bit or 8-bit functions. */
+ if (s->two_byte_p)
+ XDrawString16 (s->display, s->window, s->gc, x,
+ s->ybase - boff, s->char2b, s->nchars);
+ else
+ XDrawString (s->display, s->window, s->gc, x,
+ s->ybase - boff, char1b, s->nchars);
+ }
+ else
+ {
+ if (s->two_byte_p)
+ XDrawImageString16 (s->display, s->window, s->gc, x,
+ s->ybase - boff, s->char2b, s->nchars);
+ else
+ XDrawImageString (s->display, s->window, s->gc, x,
+ s->ybase - boff, char1b, s->nchars);
+ }
+
+ if (s->face->overstrike)
+ {
+ /* For overstriking (to simulate bold-face), draw the
+ characters again shifted to the right by one pixel. */
+ if (s->two_byte_p)
+ XDrawString16 (s->display, s->window, s->gc, x + 1,
+ s->ybase - boff, s->char2b, s->nchars);
+ else
+ XDrawString (s->display, s->window, s->gc, x + 1,
+ s->ybase - boff, char1b, s->nchars);
+ }
+ }
+ }
+
+ /* Draw the foreground of composite glyph string S. */
+
+ static void
+ x_draw_composite_glyph_string_foreground (s)
+ struct glyph_string *s;
+ {
+ int i, x;
+
+ /* If first glyph of S has a left box line, start drawing the text
+ of S to the right of that box line. */
+ if (s->face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p)
+ x = s->x + abs (s->face->box_line_width);
+ else
+ x = s->x;
+
+ /* S is a glyph string for a composition. S->gidx is the index of
+ the first character drawn for glyphs of this composition.
+ S->gidx == 0 means we are drawing the very first character of
+ this composition. */
+
+ /* Draw a rectangle for the composition if the font for the very
+ first character of the composition could not be loaded. */
+ if (s->font_not_found_p)
+ {
+ if (s->gidx == 0)
+ XDrawRectangle (s->display, s->window, s->gc, x, s->y,
+ s->width - 1, s->height - 1);
+ }
+ else
+ {
+ for (i = 0; i < s->nchars; i++, ++s->gidx)
+ {
+ XDrawString16 (s->display, s->window, s->gc,
+ x + s->cmp->offsets[s->gidx * 2],
+ s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
+ s->char2b + i, 1);
+ if (s->face->overstrike)
+ XDrawString16 (s->display, s->window, s->gc,
+ x + s->cmp->offsets[s->gidx * 2] + 1,
+ s->ybase - s->cmp->offsets[s->gidx * 2 + 1],
+ s->char2b + i, 1);
+ }
+ }
+ }
+
+
+ #ifdef USE_X_TOOLKIT
+
+ static struct frame *x_frame_of_widget P_ ((Widget));
+ static Boolean cvt_string_to_pixel P_ ((Display *, XrmValue *, Cardinal *,
+ XrmValue *, XrmValue *, XtPointer *));
+ static void cvt_pixel_dtor P_ ((XtAppContext, XrmValue *, XtPointer,
+ XrmValue *, Cardinal *));
+
+
+ /* Return the frame on which widget WIDGET is used.. Abort if frame
+ cannot be determined. */
+
+ static struct frame *
+ x_frame_of_widget (widget)
+ Widget widget;
+ {
+ struct x_display_info *dpyinfo;
+ Lisp_Object tail;
+ struct frame *f;
+
+ dpyinfo = x_display_info_for_display (XtDisplay (widget));
+
+ /* Find the top-level shell of the widget. Note that this function
+ can be called when the widget is not yet realized, so XtWindow
+ (widget) == 0. That's the reason we can't simply use
+ x_any_window_to_frame. */
+ while (!XtIsTopLevelShell (widget))
+ widget = XtParent (widget);
+
+ /* Look for a frame with that top-level widget. Allocate the color
+ on that frame to get the right gamma correction value. */
+ for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
+ if (GC_FRAMEP (XCAR (tail))
+ && (f = XFRAME (XCAR (tail)),
+ (f->output_data.nothing != 1
+ && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
+ && f->output_data.x->widget == widget)
+ return f;
+
+ abort ();
+ }
+
+
+ /* Allocate the color COLOR->pixel on the screen and display of
+ widget WIDGET in colormap CMAP. If an exact match cannot be
+ allocated, try the nearest color available. Value is non-zero
+ if successful. This is called from lwlib. */
+
+ int
+ x_alloc_nearest_color_for_widget (widget, cmap, color)
+ Widget widget;
+ Colormap cmap;
+ XColor *color;
+ {
+ struct frame *f = x_frame_of_widget (widget);
+ return x_alloc_nearest_color (f, cmap, color);
+ }
+
+
+ /* Allocate a color which is lighter or darker than *PIXEL by FACTOR
+ or DELTA. Try a color with RGB values multiplied by FACTOR first.
+ If this produces the same color as PIXEL, try a color where all RGB
+ values have DELTA added. Return the allocated color in *PIXEL.
+ DISPLAY is the X display, CMAP is the colormap to operate on.
+ Value is non-zero if successful. */
+
+ int
+ x_alloc_lighter_color_for_widget (widget, display, cmap, pixel, factor, delta)
+ Widget widget;
+ Display *display;
+ Colormap cmap;
+ unsigned long *pixel;
+ double factor;
+ int delta;
+ {
+ struct frame *f = x_frame_of_widget (widget);
+ return x_alloc_lighter_color (f, display, cmap, pixel, factor, delta);
+ }
+
+
+ /* Structure specifying which arguments should be passed by Xt to
+ cvt_string_to_pixel. We want the widget's screen and colormap. */
+
+ static XtConvertArgRec cvt_string_to_pixel_args[] =
+ {
+ {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.screen),
+ sizeof (Screen *)},
+ {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.colormap),
+ sizeof (Colormap)}
+ };
+
+
+ /* The address of this variable is returned by
+ cvt_string_to_pixel. */
+
+ static Pixel cvt_string_to_pixel_value;
+
+
+ /* Convert a color name to a pixel color.
+
+ DPY is the display we are working on.
+
+ ARGS is an array of *NARGS XrmValue structures holding additional
+ information about the widget for which the conversion takes place.
+ The contents of this array are determined by the specification
+ in cvt_string_to_pixel_args.
+
+ FROM is a pointer to an XrmValue which points to the color name to
+ convert. TO is an XrmValue in which to return the pixel color.
+
+ CLOSURE_RET is a pointer to user-data, in which we record if
+ we allocated the color or not.
+
+ Value is True if successful, False otherwise. */
+
+ static Boolean
+ cvt_string_to_pixel (dpy, args, nargs, from, to, closure_ret)
+ Display *dpy;
+ XrmValue *args;
+ Cardinal *nargs;
+ XrmValue *from, *to;
+ XtPointer *closure_ret;
+ {
+ Screen *screen;
+ Colormap cmap;
+ Pixel pixel;
+ String color_name;
+ XColor color;
+
+ if (*nargs != 2)
+ {
+ XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
+ "wrongParameters", "cvt_string_to_pixel",
+ "XtToolkitError",
+ "Screen and colormap args required", NULL, NULL);
+ return False;
+ }
+
+ screen = *(Screen **) args[0].addr;
+ cmap = *(Colormap *) args[1].addr;
+ color_name = (String) from->addr;
+
+ if (strcmp (color_name, XtDefaultBackground) == 0)
+ {
+ *closure_ret = (XtPointer) False;
+ pixel = WhitePixelOfScreen (screen);
+ }
+ else if (strcmp (color_name, XtDefaultForeground) == 0)
+ {
+ *closure_ret = (XtPointer) False;
+ pixel = BlackPixelOfScreen (screen);
+ }
+ else if (XParseColor (dpy, cmap, color_name, &color)
+ && x_alloc_nearest_color_1 (dpy, cmap, &color))
+ {
+ pixel = color.pixel;
+ *closure_ret = (XtPointer) True;
+ }
+ else
+ {
+ String params[1];
+ Cardinal nparams = 1;
+
+ params[0] = color_name;
+ XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
+ "badValue", "cvt_string_to_pixel",
+ "XtToolkitError", "Invalid color `%s'",
+ params, &nparams);
+ return False;
+ }
+
+ if (to->addr != NULL)
+ {
+ if (to->size < sizeof (Pixel))
+ {
+ to->size = sizeof (Pixel);
+ return False;
+ }
+
+ *(Pixel *) to->addr = pixel;
+ }
+ else
+ {
+ cvt_string_to_pixel_value = pixel;
+ to->addr = (XtPointer) &cvt_string_to_pixel_value;
+ }
+
+ to->size = sizeof (Pixel);
+ return True;
+ }
+
+
+ /* Free a pixel color which was previously allocated via
+ cvt_string_to_pixel. This is registered as the destructor
+ for this type of resource via XtSetTypeConverter.
+
+ APP is the application context in which we work.
+
+ TO is a pointer to an XrmValue holding the color to free.
+ CLOSURE is the value we stored in CLOSURE_RET for this color
+ in cvt_string_to_pixel.
+
+ ARGS and NARGS are like for cvt_string_to_pixel. */
+
+ static void
+ cvt_pixel_dtor (app, to, closure, args, nargs)
+ XtAppContext app;
+ XrmValuePtr to;
+ XtPointer closure;
+ XrmValuePtr args;
+ Cardinal *nargs;
+ {
+ if (*nargs != 2)
+ {
+ XtAppWarningMsg (app, "wrongParameters", "cvt_pixel_dtor",
+ "XtToolkitError",
+ "Screen and colormap arguments required",
+ NULL, NULL);
+ }
+ else if (closure != NULL)
+ {
+ /* We did allocate the pixel, so free it. */
+ Screen *screen = *(Screen **) args[0].addr;
+ Colormap cmap = *(Colormap *) args[1].addr;
+ x_free_dpy_colors (DisplayOfScreen (screen), screen, cmap,
+ (Pixel *) to->addr, 1);
+ }
+ }
+
+
+ #endif /* USE_X_TOOLKIT */
+
+
+ /* Value is an array of XColor structures for the contents of the
+ color map of display DPY. Set *NCELLS to the size of the array.
+ Note that this probably shouldn't be called for large color maps,
+ say a 24-bit TrueColor map. */
+
+ static const XColor *
+ x_color_cells (dpy, ncells)
+ Display *dpy;
+ int *ncells;
+ {
+ struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
+
+ if (dpyinfo->color_cells == NULL)
+ {
+ Screen *screen = dpyinfo->screen;
+ int i;
+
+ dpyinfo->ncolor_cells
+ = XDisplayCells (dpy, XScreenNumberOfScreen (screen));
+ dpyinfo->color_cells
+ = (XColor *) xmalloc (dpyinfo->ncolor_cells
+ * sizeof *dpyinfo->color_cells);
+
+ for (i = 0; i < dpyinfo->ncolor_cells; ++i)
+ dpyinfo->color_cells[i].pixel = i;
+
+ XQueryColors (dpy, dpyinfo->cmap,
+ dpyinfo->color_cells, dpyinfo->ncolor_cells);
+ }
+
+ *ncells = dpyinfo->ncolor_cells;
+ return dpyinfo->color_cells;
+ }
+
+
+ /* On frame F, translate pixel colors to RGB values for the NCOLORS
+ colors in COLORS. Use cached information, if available. */
+
+ void
+ x_query_colors (f, colors, ncolors)
+ struct frame *f;
+ XColor *colors;
+ int ncolors;
+ {
+ struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+
+ if (dpyinfo->color_cells)
+ {
+ int i;
+ for (i = 0; i < ncolors; ++i)
+ {
+ unsigned long pixel = colors[i].pixel;
+ xassert (pixel < dpyinfo->ncolor_cells);
+ xassert (dpyinfo->color_cells[pixel].pixel == pixel);
+ colors[i] = dpyinfo->color_cells[pixel];
+ }
+ }
+ else
+ XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors);
+ }
+
+
+ /* On frame F, translate pixel color to RGB values for the color in
+ COLOR. Use cached information, if available. */
+
+ void
+ x_query_color (f, color)
+ struct frame *f;
+ XColor *color;
+ {
+ x_query_colors (f, color, 1);
+ }
+
+
+ /* Allocate the color COLOR->pixel on DISPLAY, colormap CMAP. If an
+ exact match can't be allocated, try the nearest color available.
+ Value is non-zero if successful. Set *COLOR to the color
+ allocated. */
+
+ static int
+ x_alloc_nearest_color_1 (dpy, cmap, color)
+ Display *dpy;
+ Colormap cmap;
+ XColor *color;
+ {
+ int rc;
+
+ rc = XAllocColor (dpy, cmap, color);
+ if (rc == 0)
+ {
+ /* If we got to this point, the colormap is full, so we're going
+ to try to get the next closest color. The algorithm used is
+ a least-squares matching, which is what X uses for closest
+ color matching with StaticColor visuals. */
+ int nearest, i;
+ unsigned long nearest_delta = ~0;
+ int ncells;
+ const XColor *cells = x_color_cells (dpy, &ncells);
+
+ for (nearest = i = 0; i < ncells; ++i)
+ {
+ long dred = (color->red >> 8) - (cells[i].red >> 8);
+ long dgreen = (color->green >> 8) - (cells[i].green >> 8);
+ long dblue = (color->blue >> 8) - (cells[i].blue >> 8);
+ unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
+
+ if (delta < nearest_delta)
+ {
+ nearest = i;
+ nearest_delta = delta;
+ }
+ }
+
+ color->red = cells[nearest].red;
+ color->green = cells[nearest].green;
+ color->blue = cells[nearest].blue;
+ rc = XAllocColor (dpy, cmap, color);
+ }
+ else
+ {
+ /* If allocation succeeded, and the allocated pixel color is not
+ equal to a cached pixel color recorded earlier, there was a
+ change in the colormap, so clear the color cache. */
+ struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
+ XColor *cached_color;
+
+ if (dpyinfo->color_cells
+ && (cached_color = &dpyinfo->color_cells[color->pixel],
+ (cached_color->red != color->red
+ || cached_color->blue != color->blue
+ || cached_color->green != color->green)))
+ {
+ xfree (dpyinfo->color_cells);
+ dpyinfo->color_cells = NULL;
+ dpyinfo->ncolor_cells = 0;
+ }
+ }
+
+ #ifdef DEBUG_X_COLORS
+ if (rc)
+ register_color (color->pixel);
+ #endif /* DEBUG_X_COLORS */
+
+ return rc;
+ }
+
+
+ /* Allocate the color COLOR->pixel on frame F, colormap CMAP. If an
+ exact match can't be allocated, try the nearest color available.
+ Value is non-zero if successful. Set *COLOR to the color
+ allocated. */
+
+ int
+ x_alloc_nearest_color (f, cmap, color)
+ struct frame *f;
+ Colormap cmap;
+ XColor *color;
+ {
+ gamma_correct (f, color);
+ return x_alloc_nearest_color_1 (FRAME_X_DISPLAY (f), cmap, color);
+ }
+
+
+ /* Allocate color PIXEL on frame F. PIXEL must already be allocated.
+ It's necessary to do this instead of just using PIXEL directly to
+ get color reference counts right. */
+
+ unsigned long
+ x_copy_color (f, pixel)
+ struct frame *f;
+ unsigned long pixel;
+ {
+ XColor color;
+
+ color.pixel = pixel;
+ BLOCK_INPUT;
+ x_query_color (f, &color);
+ XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
+ UNBLOCK_INPUT;
+ #ifdef DEBUG_X_COLORS
+ register_color (pixel);
+ #endif
+ return color.pixel;
+ }
+
+
+ /* Allocate color PIXEL on display DPY. PIXEL must already be allocated.
+ It's necessary to do this instead of just using PIXEL directly to
+ get color reference counts right. */
+
+ unsigned long
+ x_copy_dpy_color (dpy, cmap, pixel)
+ Display *dpy;
+ Colormap cmap;
+ unsigned long pixel;
+ {
+ XColor color;
+
+ color.pixel = pixel;
+ BLOCK_INPUT;
+ XQueryColor (dpy, cmap, &color);
+ XAllocColor (dpy, cmap, &color);
+ UNBLOCK_INPUT;
+ #ifdef DEBUG_X_COLORS
+ register_color (pixel);
+ #endif
+ return color.pixel;
+ }
+
+
+ /* Brightness beyond which a color won't have its highlight brightness
+ boosted.
+
+ Nominally, highlight colors for `3d' faces are calculated by
+ brightening an object's color by a constant scale factor, but this
+ doesn't yield good results for dark colors, so for colors who's
+ brightness is less than this value (on a scale of 0-65535) have an
+ use an additional additive factor.
+
+ The value here is set so that the default menu-bar/mode-line color
+ (grey75) will not have its highlights changed at all. */
+ #define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000
+
+
+ /* Allocate a color which is lighter or darker than *PIXEL by FACTOR
+ or DELTA. Try a color with RGB values multiplied by FACTOR first.
+ If this produces the same color as PIXEL, try a color where all RGB
+ values have DELTA added. Return the allocated color in *PIXEL.
+ DISPLAY is the X display, CMAP is the colormap to operate on.
+ Value is non-zero if successful. */
+
+ static int
+ x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
+ struct frame *f;
+ Display *display;
+ Colormap cmap;
+ unsigned long *pixel;
+ double factor;
+ int delta;
+ {
+ XColor color, new;
+ long bright;
+ int success_p;
+
+ /* Get RGB color values. */
+ color.pixel = *pixel;
+ x_query_color (f, &color);
+
+ /* Change RGB values by specified FACTOR. Avoid overflow! */
+ xassert (factor >= 0);
+ new.red = min (0xffff, factor * color.red);
+ new.green = min (0xffff, factor * color.green);
+ new.blue = min (0xffff, factor * color.blue);
+
+ /* Calculate brightness of COLOR. */
+ bright = (2 * color.red + 3 * color.green + color.blue) / 6;
+
+ /* We only boost colors that are darker than
+ HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */
+ if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
+ /* Make an additive adjustment to NEW, because it's dark enough so
+ that scaling by FACTOR alone isn't enough. */
+ {
+ /* How far below the limit this color is (0 - 1, 1 being darker). */
+ double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
+ /* The additive adjustment. */
+ int min_delta = delta * dimness * factor / 2;
+
+ if (factor < 1)
+ {
+ new.red = max (0, new.red - min_delta);
+ new.green = max (0, new.green - min_delta);
+ new.blue = max (0, new.blue - min_delta);
+ }
+ else
+ {
+ new.red = min (0xffff, min_delta + new.red);
+ new.green = min (0xffff, min_delta + new.green);
+ new.blue = min (0xffff, min_delta + new.blue);
+ }
+ }
+
+ /* Try to allocate the color. */
+ success_p = x_alloc_nearest_color (f, cmap, &new);
+ if (success_p)
+ {
+ if (new.pixel == *pixel)
+ {
+ /* If we end up with the same color as before, try adding
+ delta to the RGB values. */
+ x_free_colors (f, &new.pixel, 1);
+
+ new.red = min (0xffff, delta + color.red);
+ new.green = min (0xffff, delta + color.green);
+ new.blue = min (0xffff, delta + color.blue);
+ success_p = x_alloc_nearest_color (f, cmap, &new);
+ }
+ else
+ success_p = 1;
+ *pixel = new.pixel;
+ }
+
+ return success_p;
+ }
+
+
+ /* Set up the foreground color for drawing relief lines of glyph
+ string S. RELIEF is a pointer to a struct relief containing the GC
+ with which lines will be drawn. Use a color that is FACTOR or
+ DELTA lighter or darker than the relief's background which is found
+ in S->f->output_data.x->relief_background. If such a color cannot
+ be allocated, use DEFAULT_PIXEL, instead. */
+
+ static void
+ x_setup_relief_color (f, relief, factor, delta, default_pixel)
+ struct frame *f;
+ struct relief *relief;
+ double factor;
+ int delta;
+ unsigned long default_pixel;
+ {
+ XGCValues xgcv;
+ struct x_output *di = f->output_data.x;
+ unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
+ unsigned long pixel;
+ unsigned long background = di->relief_background;
+ Colormap cmap = FRAME_X_COLORMAP (f);
+ struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ Display *dpy = FRAME_X_DISPLAY (f);
+
+ xgcv.graphics_exposures = False;
+ xgcv.line_width = 1;
+
+ /* Free previously allocated color. The color cell will be reused
+ when it has been freed as many times as it was allocated, so this
+ doesn't affect faces using the same colors. */
+ if (relief->gc
+ && relief->allocated_p)
+ {
+ x_free_colors (f, &relief->pixel, 1);
+ relief->allocated_p = 0;
+ }
+
+ /* Allocate new color. */
+ xgcv.foreground = default_pixel;
+ pixel = background;
+ if (dpyinfo->n_planes != 1
+ && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
+ {
+ relief->allocated_p = 1;
+ xgcv.foreground = relief->pixel = pixel;
+ }
+
+ if (relief->gc == 0)
+ {
+ xgcv.stipple = dpyinfo->gray;
+ mask |= GCStipple;
+ relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
+ }
+ else
+ XChangeGC (dpy, relief->gc, mask, &xgcv);
+ }
+
+
+ /* Set up colors for the relief lines around glyph string S. */
+
+ static void
+ x_setup_relief_colors (s)
+ struct glyph_string *s;
+ {
+ struct x_output *di = s->f->output_data.x;
+ unsigned long color;
+
+ if (s->face->use_box_color_for_shadows_p)
+ color = s->face->box_color;
+ else if (s->first_glyph->type == IMAGE_GLYPH
+ && s->img->pixmap
+ && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
+ color = IMAGE_BACKGROUND (s->img, s->f, 0);
+ else
+ {
+ XGCValues xgcv;
+
+ /* Get the background color of the face. */
+ XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
+ color = xgcv.background;
+ }
+
+ if (di->white_relief.gc == 0
+ || color != di->relief_background)
+ {
+ di->relief_background = color;
+ x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
+ WHITE_PIX_DEFAULT (s->f));
+ x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
+ BLACK_PIX_DEFAULT (s->f));
+ }
+ }
+
+
+ /* Draw a relief on frame F inside the rectangle given by LEFT_X,
+ TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief
+ to draw, it must be >= 0. RAISED_P non-zero means draw a raised
+ relief. LEFT_P non-zero means draw a relief on the left side of
+ the rectangle. RIGHT_P non-zero means draw a relief on the right
+ side of the rectangle. CLIP_RECT is the clipping rectangle to use
+ when drawing. */
+
+ static void
+ x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
+ raised_p, left_p, right_p, clip_rect)
+ struct frame *f;
+ int left_x, top_y, right_x, bottom_y, width, left_p, right_p, raised_p;
+ XRectangle *clip_rect;
+ {
+ Display *dpy = FRAME_X_DISPLAY (f);
+ Window window = FRAME_X_WINDOW (f);
+ int i;
+ GC gc;
+
+ if (raised_p)
+ gc = f->output_data.x->white_relief.gc;
+ else
+ gc = f->output_data.x->black_relief.gc;
+ XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
+
+ /* Top. */
+ for (i = 0; i < width; ++i)
+ XDrawLine (dpy, window, gc,
+ left_x + i * left_p, top_y + i,
+ right_x + 1 - i * right_p, top_y + i);
+
+ /* Left. */
+ if (left_p)
+ for (i = 0; i < width; ++i)
+ XDrawLine (dpy, window, gc,
+ left_x + i, top_y + i, left_x + i, bottom_y - i + 1);
+
+ XSetClipMask (dpy, gc, None);
+ if (raised_p)
+ gc = f->output_data.x->black_relief.gc;
+ else
+ gc = f->output_data.x->white_relief.gc;
+ XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
+
+ /* Bottom. */
+ for (i = 0; i < width; ++i)
+ XDrawLine (dpy, window, gc,
+ left_x + i * left_p, bottom_y - i,
+ right_x + 1 - i * right_p, bottom_y - i);
+
+ /* Right. */
+ if (right_p)
+ for (i = 0; i < width; ++i)
+ XDrawLine (dpy, window, gc,
+ right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
+
+ XSetClipMask (dpy, gc, None);
+ }
+
+
+ /* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
+ RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the lines to
+ draw, it must be >= 0. LEFT_P non-zero means draw a line on the
+ left side of the rectangle. RIGHT_P non-zero means draw a line
+ on the right side of the rectangle. CLIP_RECT is the clipping
+ rectangle to use when drawing. */
+
+ static void
+ x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
+ left_p, right_p, clip_rect)
+ struct glyph_string *s;
+ int left_x, top_y, right_x, bottom_y, width, left_p, right_p;
+ XRectangle *clip_rect;
+ {
+ XGCValues xgcv;
+
+ XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
+ XSetForeground (s->display, s->gc, s->face->box_color);
+ XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
+
+ /* Top. */
+ XFillRectangle (s->display, s->window, s->gc,
+ left_x, top_y, right_x - left_x + 1, width);
+
+ /* Left. */
+ if (left_p)
+ XFillRectangle (s->display, s->window, s->gc,
+ left_x, top_y, width, bottom_y - top_y + 1);
+
+ /* Bottom. */
+ XFillRectangle (s->display, s->window, s->gc,
+ left_x, bottom_y - width + 1, right_x - left_x + 1, width);
+
+ /* Right. */
+ if (right_p)
+ XFillRectangle (s->display, s->window, s->gc,
+ right_x - width + 1, top_y, width, bottom_y - top_y + 1);
+
+ XSetForeground (s->display, s->gc, xgcv.foreground);
+ XSetClipMask (s->display, s->gc, None);
+ }
+
+
+ /* Draw a box around glyph string S. */
+
+ static void
+ x_draw_glyph_string_box (s)
+ struct glyph_string *s;
+ {
+ int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
+ int left_p, right_p;
+ struct glyph *last_glyph;
+ XRectangle clip_rect;
+
+ last_x = window_box_right (s->w, s->area);
+ if (s->row->full_width_p
+ && !s->w->pseudo_window_p)
+ {
+ last_x += WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH (s->w);
+ if (s->area != RIGHT_MARGIN_AREA
+ || WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (s->w))
+ last_x += WINDOW_RIGHT_FRINGE_WIDTH (s->w);
+ }
+
+ /* The glyph that may have a right box line. */
+ last_glyph = (s->cmp || s->img
+ ? s->first_glyph
+ : s->first_glyph + s->nchars - 1);
+
+ width = abs (s->face->box_line_width);
+ raised_p = s->face->box == FACE_RAISED_BOX;
+ left_x = s->x;
+ right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
+ ? last_x - 1
+ : min (last_x, s->x + s->background_width) - 1);
+ top_y = s->y;
+ bottom_y = top_y + s->height - 1;
+
+ left_p = (s->first_glyph->left_box_line_p
+ || (s->hl == DRAW_MOUSE_FACE
+ && (s->prev == NULL
+ || s->prev->hl != s->hl)));
+ right_p = (last_glyph->right_box_line_p
+ || (s->hl == DRAW_MOUSE_FACE
+ && (s->next == NULL
+ || s->next->hl != s->hl)));
+
+ get_glyph_string_clip_rect (s, &clip_rect);
+
+ if (s->face->box == FACE_SIMPLE_BOX)
+ x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
+ left_p, right_p, &clip_rect);
+ else
+ {
+ x_setup_relief_colors (s);
+ x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
+ width, raised_p, left_p, right_p, &clip_rect);
+ }
+ }
+
+
+ /* Draw foreground of image glyph string S. */
+
+ static void
+ x_draw_image_foreground (s)
+ struct glyph_string *s;
+ {
+ int x;
+ int y = s->ybase - image_ascent (s->img, s->face);
+
+ /* If first glyph of S has a left box line, start drawing it to the
+ right of that line. */
+ if (s->face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p)
+ x = s->x + abs (s->face->box_line_width);
+ else
+ x = s->x;
+
+ /* If there is a margin around the image, adjust x- and y-position
+ by that margin. */
+ x += s->img->hmargin;
+ y += s->img->vmargin;
+
+ if (s->img->pixmap)
+ {
+ if (s->img->mask)
+ {
+ /* We can't set both a clip mask and use XSetClipRectangles
+ because the latter also sets a clip mask. We also can't
+ trust on the shape extension to be available
+ (XShapeCombineRegion). So, compute the rectangle to draw
+ manually. */
+ unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
+ | GCFunction);
+ XGCValues xgcv;
+ XRectangle clip_rect, image_rect, r;
+
+ xgcv.clip_mask = s->img->mask;
+ xgcv.clip_x_origin = x;
+ xgcv.clip_y_origin = y;
+ xgcv.function = GXcopy;
+ XChangeGC (s->display, s->gc, mask, &xgcv);
+
+ get_glyph_string_clip_rect (s, &clip_rect);
+ image_rect.x = x;
+ image_rect.y = y;
+ image_rect.width = s->img->width;
+ image_rect.height = s->img->height;
+ if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
+ XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
+ r.x - x, r.y - y, r.width, r.height, r.x, r.y);
+ }
+ else
+ {
+ XRectangle clip_rect, image_rect, r;
+
+ get_glyph_string_clip_rect (s, &clip_rect);
+ image_rect.x = x;
+ image_rect.y = y;
+ image_rect.width = s->img->width;
+ image_rect.height = s->img->height;
+ if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
+ XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
+ r.x - x, r.y - y, r.width, r.height, r.x, r.y);
+
+ /* When the image has a mask, we can expect that at
+ least part of a mouse highlight or a block cursor will
+ be visible. If the image doesn't have a mask, make
+ a block cursor visible by drawing a rectangle around
+ the image. I believe it's looking better if we do
+ nothing here for mouse-face. */
+ if (s->hl == DRAW_CURSOR)
+ {
+ int r = s->img->relief;
+ if (r < 0) r = -r;
+ XDrawRectangle (s->display, s->window, s->gc, x - r, y - r,
+ s->img->width + r*2 - 1, s->img->height + r*2 -
1);
+ }
+ }
+ }
+ else
+ /* Draw a rectangle if image could not be loaded. */
+ XDrawRectangle (s->display, s->window, s->gc, x, y,
+ s->img->width - 1, s->img->height - 1);
+ }
+
+
+ /* Draw a relief around the image glyph string S. */
+
+ static void
+ x_draw_image_relief (s)
+ struct glyph_string *s;
+ {
+ int x0, y0, x1, y1, thick, raised_p;
+ XRectangle r;
+ int x;
+ int y = s->ybase - image_ascent (s->img, s->face);
+
+ /* If first glyph of S has a left box line, start drawing it to the
+ right of that line. */
+ if (s->face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p)
+ x = s->x + abs (s->face->box_line_width);
+ else
+ x = s->x;
+
+ /* If there is a margin around the image, adjust x- and y-position
+ by that margin. */
+ x += s->img->hmargin;
+ y += s->img->vmargin;
+
+ if (s->hl == DRAW_IMAGE_SUNKEN
+ || s->hl == DRAW_IMAGE_RAISED)
+ {
+ thick = tool_bar_button_relief >= 0 ? tool_bar_button_relief :
DEFAULT_TOOL_BAR_BUTTON_RELIEF;
+ raised_p = s->hl == DRAW_IMAGE_RAISED;
+ }
+ else
+ {
+ thick = abs (s->img->relief);
+ raised_p = s->img->relief > 0;
+ }
+
+ x0 = x - thick;
+ y0 = y - thick;
+ x1 = x + s->img->width + thick - 1;
+ y1 = y + s->img->height + thick - 1;
+
+ x_setup_relief_colors (s);
+ get_glyph_string_clip_rect (s, &r);
+ x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
+ }
+
+
+ /* Draw the foreground of image glyph string S to PIXMAP. */
+
+ static void
+ x_draw_image_foreground_1 (s, pixmap)
+ struct glyph_string *s;
+ Pixmap pixmap;
+ {
+ int x;
+ int y = s->ybase - s->y - image_ascent (s->img, s->face);
+
+ /* If first glyph of S has a left box line, start drawing it to the
+ right of that line. */
+ if (s->face->box != FACE_NO_BOX
+ && s->first_glyph->left_box_line_p)
+ x = abs (s->face->box_line_width);
+ else
+ x = 0;
+
+ /* If there is a margin around the image, adjust x- and y-position
+ by that margin. */
+ x += s->img->hmargin;
+ y += s->img->vmargin;
+
+ if (s->img->pixmap)
+ {
+ if (s->img->mask)
+ {
+ /* We can't set both a clip mask and use XSetClipRectangles
+ because the latter also sets a clip mask. We also can't
+ trust on the shape extension to be available
+ (XShapeCombineRegion). So, compute the rectangle to draw
+ manually. */
+ unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
+ | GCFunction);
+ XGCValues xgcv;
+
+ xgcv.clip_mask = s->img->mask;
+ xgcv.clip_x_origin = x;
+ xgcv.clip_y_origin = y;
+ xgcv.function = GXcopy;
+ XChangeGC (s->display, s->gc, mask, &xgcv);
+
+ XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
+ 0, 0, s->img->width, s->img->height, x, y);
+ XSetClipMask (s->display, s->gc, None);
+ }
+ else
+ {
+ XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
+ 0, 0, s->img->width, s->img->height, x, y);
+
+ /* When the image has a mask, we can expect that at
+ least part of a mouse highlight or a block cursor will
+ be visible. If the image doesn't have a mask, make
+ a block cursor visible by drawing a rectangle around
+ the image. I believe it's looking better if we do
+ nothing here for mouse-face. */
+ if (s->hl == DRAW_CURSOR)
+ {
+ int r = s->img->relief;
+ if (r < 0) r = -r;
+ XDrawRectangle (s->display, s->window, s->gc, x - r, y - r,
+ s->img->width + r*2 - 1, s->img->height + r*2 -
1);
+ }
+ }
+ }
+ else
+ /* Draw a rectangle if image could not be loaded. */
+ XDrawRectangle (s->display, pixmap, s->gc, x, y,
+ s->img->width - 1, s->img->height - 1);
+ }
+
+
+ /* Draw part of the background of glyph string S. X, Y, W, and H
+ give the rectangle to draw. */
+
+ static void
+ x_draw_glyph_string_bg_rect (s, x, y, w, h)
+ struct glyph_string *s;
+ int x, y, w, h;
+ {
+ if (s->stippled_p)
+ {
+ /* Fill background with a stipple pattern. */
+ XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
+ XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
+ XSetFillStyle (s->display, s->gc, FillSolid);
+ }
+ else
+ x_clear_glyph_string_rect (s, x, y, w, h);
+ }
+
+
+ /* Draw image glyph string S.
+
+ s->y
+ s->x +-------------------------
+ | s->face->box
+ |
+ | +-------------------------
+ | | s->img->margin
+ | |
+ | | +-------------------
+ | | | the image
+
+ */
+
+ static void
+ x_draw_image_glyph_string (s)
+ struct glyph_string *s;
+ {
+ int x, y;
+ int box_line_hwidth = abs (s->face->box_line_width);
+ int box_line_vwidth = max (s->face->box_line_width, 0);
+ int height;
+ Pixmap pixmap = None;
+
+ height = s->height - 2 * box_line_vwidth;
+
+
+ /* Fill background with face under the image. Do it only if row is
+ taller than image or if image has a clip mask to reduce
+ flickering. */
+ s->stippled_p = s->face->stipple != 0;
+ if (height > s->img->height
+ || s->img->hmargin
+ || s->img->vmargin
+ || s->img->mask
+ || s->img->pixmap == 0
+ || s->width != s->background_width)
+ {
+ if (box_line_hwidth && s->first_glyph->left_box_line_p)
+ x = s->x + box_line_hwidth;
+ else
+ x = s->x;
+
+ y = s->y + box_line_vwidth;
+
+ if (s->img->mask)
+ {
+ /* Create a pixmap as large as the glyph string. Fill it
+ with the background color. Copy the image to it, using
+ its mask. Copy the temporary pixmap to the display. */
+ Screen *screen = FRAME_X_SCREEN (s->f);
+ int depth = DefaultDepthOfScreen (screen);
+
+ /* Create a pixmap as large as the glyph string. */
+ pixmap = XCreatePixmap (s->display, s->window,
+ s->background_width,
+ s->height, depth);
+
+ /* Don't clip in the following because we're working on the
+ pixmap. */
+ XSetClipMask (s->display, s->gc, None);
+
+ /* Fill the pixmap with the background color/stipple. */
+ if (s->stippled_p)
+ {
+ /* Fill background with a stipple pattern. */
+ XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
+ XFillRectangle (s->display, pixmap, s->gc,
+ 0, 0, s->background_width, s->height);
+ XSetFillStyle (s->display, s->gc, FillSolid);
+ }
+ else
+ {
+ XGCValues xgcv;
+ XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
+ &xgcv);
+ XSetForeground (s->display, s->gc, xgcv.background);
+ XFillRectangle (s->display, pixmap, s->gc,
+ 0, 0, s->background_width, s->height);
+ XSetForeground (s->display, s->gc, xgcv.foreground);
+ }
+ }
+ else
+ x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
+
+ s->background_filled_p = 1;
+ }
+
+ /* Draw the foreground. */
+ if (pixmap != None)
+ {
+ x_draw_image_foreground_1 (s, pixmap);
+ x_set_glyph_string_clipping (s);
+ XCopyArea (s->display, pixmap, s->window, s->gc,
+ 0, 0, s->background_width, s->height, s->x, s->y);
+ XFreePixmap (s->display, pixmap);
+ }
+ else
+ x_draw_image_foreground (s);
+
+ /* If we must draw a relief around the image, do it. */
+ if (s->img->relief
+ || s->hl == DRAW_IMAGE_RAISED
+ || s->hl == DRAW_IMAGE_SUNKEN)
+ x_draw_image_relief (s);
+ }
+
+
+ /* Draw stretch glyph string S. */
+
+ static void
+ x_draw_stretch_glyph_string (s)
+ struct glyph_string *s;
+ {
+ xassert (s->first_glyph->type == STRETCH_GLYPH);
+ s->stippled_p = s->face->stipple != 0;
+
+ if (s->hl == DRAW_CURSOR
+ && !x_stretch_cursor_p)
+ {
+ /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
+ as wide as the stretch glyph. */
+ int width = min (FRAME_COLUMN_WIDTH (s->f), s->background_width);
+
+ /* Draw cursor. */
+ x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
+
+ /* Clear rest using the GC of the original non-cursor face. */
+ if (width < s->background_width)
+ {
+ int x = s->x + width, y = s->y;
+ int w = s->background_width - width, h = s->height;
+ XRectangle r;
+ GC gc;
+
+ if (s->row->mouse_face_p
+ && cursor_in_mouse_face_p (s->w))
+ {
+ x_set_mouse_face_gc (s);
+ gc = s->gc;
+ }
+ else
+ gc = s->face->gc;
+
+ get_glyph_string_clip_rect (s, &r);
+ XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
+
+ if (s->face->stipple)
+ {
+ /* Fill background with a stipple pattern. */
+ XSetFillStyle (s->display, gc, FillOpaqueStippled);
+ XFillRectangle (s->display, s->window, gc, x, y, w, h);
+ XSetFillStyle (s->display, gc, FillSolid);
+ }
+ else
+ {
+ XGCValues xgcv;
+ XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
+ XSetForeground (s->display, gc, xgcv.background);
+ XFillRectangle (s->display, s->window, gc, x, y, w, h);
+ XSetForeground (s->display, gc, xgcv.foreground);
+ }
+ }
+ }
+ else if (!s->background_filled_p)
+ x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
+ s->height);
+
+ s->background_filled_p = 1;
+ }
+
+
+ /* Draw glyph string S. */
+
+ static void
+ x_draw_glyph_string (s)
+ struct glyph_string *s;
+ {
+ int relief_drawn_p = 0;
+
+ /* If S draws into the background of its successor, draw the
+ background of the successor first so that S can draw into it.
+ This makes S->next use XDrawString instead of XDrawImageString. */
+ if (s->next && s->right_overhang && !s->for_overlaps_p)
+ {
+ xassert (s->next->img == NULL);
+ x_set_glyph_string_gc (s->next);
+ x_set_glyph_string_clipping (s->next);
+ x_draw_glyph_string_background (s->next, 1);
+ }
+
+ /* Set up S->gc, set clipping and draw S. */
+ x_set_glyph_string_gc (s);
+
+ /* Draw relief (if any) in advance for char/composition so that the
+ glyph string can be drawn over it. */
+ if (!s->for_overlaps_p
+ && s->face->box != FACE_NO_BOX
+ && (s->first_glyph->type == CHAR_GLYPH
+ || s->first_glyph->type == COMPOSITE_GLYPH))
+
+ {
+ x_set_glyph_string_clipping (s);
+ x_draw_glyph_string_background (s, 1);
+ x_draw_glyph_string_box (s);
+ x_set_glyph_string_clipping (s);
+ relief_drawn_p = 1;
+ }
+ else
+ x_set_glyph_string_clipping (s);
+
+ switch (s->first_glyph->type)
+ {
+ case IMAGE_GLYPH:
+ x_draw_image_glyph_string (s);
+ break;
+
+ case STRETCH_GLYPH:
+ x_draw_stretch_glyph_string (s);
+ break;
+
+ case CHAR_GLYPH:
+ if (s->for_overlaps_p)
+ s->background_filled_p = 1;
+ else
+ x_draw_glyph_string_background (s, 0);
+ x_draw_glyph_string_foreground (s);
+ break;
+
+ case COMPOSITE_GLYPH:
+ if (s->for_overlaps_p || s->gidx > 0)
+ s->background_filled_p = 1;
+ else
+ x_draw_glyph_string_background (s, 1);
+ x_draw_composite_glyph_string_foreground (s);
+ break;
+
+ default:
+ abort ();
+ }
+
+ if (!s->for_overlaps_p)
+ {
+ /* Draw underline. */
+ if (s->face->underline_p)
+ {
+ unsigned long tem, h;
+ int y;
+
+ /* Get the underline thickness. Default is 1 pixel. */
+ if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
+ h = 1;
+
+ /* Get the underline position. This is the recommended
+ vertical offset in pixels from the baseline to the top of
+ the underline. This is a signed value according to the
+ specs, and its default is
+
+ ROUND ((maximum descent) / 2), with
+ ROUND(x) = floor (x + 0.5) */
+
+ if (x_use_underline_position_properties
+ && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
+ y = s->ybase + (long) tem;
+ else if (s->face->font)
+ y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
+ else
+ y = s->y + s->height - h;
+
+ if (s->face->underline_defaulted_p)
+ XFillRectangle (s->display, s->window, s->gc,
+ s->x, y, s->width, h);
+ else
+ {
+ XGCValues xgcv;
+ XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
+ XSetForeground (s->display, s->gc, s->face->underline_color);
+ XFillRectangle (s->display, s->window, s->gc,
+ s->x, y, s->width, h);
+ XSetForeground (s->display, s->gc, xgcv.foreground);
+ }
+ }
+
+ /* Draw overline. */
+ if (s->face->overline_p)
+ {
+ unsigned long dy = 0, h = 1;
+
+ if (s->face->overline_color_defaulted_p)
+ XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+ s->width, h);
+ else
+ {
+ XGCValues xgcv;
+ XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
+ XSetForeground (s->display, s->gc, s->face->overline_color);
+ XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+ s->width, h);
+ XSetForeground (s->display, s->gc, xgcv.foreground);
+ }
+ }
+
+ /* Draw strike-through. */
+ if (s->face->strike_through_p)
+ {
+ unsigned long h = 1;
+ unsigned long dy = (s->height - h) / 2;
+
+ if (s->face->strike_through_color_defaulted_p)
+ XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+ s->width, h);
+ else
+ {
+ XGCValues xgcv;
+ XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
+ XSetForeground (s->display, s->gc, s->face->strike_through_color);
+ XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+ s->width, h);
+ XSetForeground (s->display, s->gc, xgcv.foreground);
+ }
+ }
+
+ /* Draw relief if not yet drawn. */
+ if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
+ x_draw_glyph_string_box (s);
+ }
+
+ /* Reset clipping. */
+ XSetClipMask (s->display, s->gc, None);
+ }
+
+ /* Shift display to make room for inserted glyphs. */
+
+ void
+ x_shift_glyphs_for_insert (f, x, y, width, height, shift_by)
+ struct frame *f;
+ int x, y, width, height, shift_by;
+ {
+ XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
+ f->output_data.x->normal_gc,
+ x, y, width, height,
+ x + shift_by, y);
+ }
+
+ /* Delete N glyphs at the nominal cursor position. Not implemented
+ for X frames. */
+
+ static void
+ x_delete_glyphs (n)
+ register int n;
+ {
+ abort ();
+ }
+
+
+ /* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
+ If they are <= 0, this is probably an error. */
+
+ void
+ x_clear_area (dpy, window, x, y, width, height, exposures)
+ Display *dpy;
+ Window window;
+ int x, y;
+ int width, height;
+ int exposures;
+ {
+ xassert (width > 0 && height > 0);
+ XClearArea (dpy, window, x, y, width, height, exposures);
+ }
+
+
+ /* Clear entire frame. If updating_frame is non-null, clear that
+ frame. Otherwise clear the selected frame. */
+
+ static void
+ x_clear_frame ()
+ {
+ struct frame *f;
+
+ if (updating_frame)
+ f = updating_frame;
+ else
+ f = SELECTED_FRAME ();
+
+ /* Clearing the frame will erase any cursor, so mark them all as no
+ longer visible. */
+ mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
+ output_cursor.hpos = output_cursor.vpos = 0;
+ output_cursor.x = -1;
+
+ /* We don't set the output cursor here because there will always
+ follow an explicit cursor_to. */
+ BLOCK_INPUT;
+ XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
+
+ /* We have to clear the scroll bars, too. If we have changed
+ colors or something like that, then they should be notified. */
+ x_scroll_bar_clear (f);
+
+ XFlush (FRAME_X_DISPLAY (f));
+
+ #ifdef USE_GTK
+ xg_frame_cleared (f);
+ #endif
+
+ UNBLOCK_INPUT;
+ }
+
+
+
+ /* Invert the middle quarter of the frame for .15 sec. */
+
+ /* We use the select system call to do the waiting, so we have to make
+ sure it's available. If it isn't, we just won't do visual bells. */
+
+ #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
+
+
+ /* Subtract the `struct timeval' values X and Y, storing the result in
+ *RESULT. Return 1 if the difference is negative, otherwise 0. */
+
+ static int
+ timeval_subtract (result, x, y)
+ struct timeval *result, x, y;
+ {
+ /* Perform the carry for the later subtraction by updating y. This
+ is safer because on some systems the tv_sec member is unsigned. */
+ if (x.tv_usec < y.tv_usec)
+ {
+ int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
+ y.tv_usec -= 1000000 * nsec;
+ y.tv_sec += nsec;
+ }
+
+ if (x.tv_usec - y.tv_usec > 1000000)
+ {
+ int nsec = (y.tv_usec - x.tv_usec) / 1000000;
+ y.tv_usec += 1000000 * nsec;
+ y.tv_sec -= nsec;
+ }
+
+ /* Compute the time remaining to wait. tv_usec is certainly
+ positive. */
+ result->tv_sec = x.tv_sec - y.tv_sec;
+ result->tv_usec = x.tv_usec - y.tv_usec;
+
+ /* Return indication of whether the result should be considered
+ negative. */
+ return x.tv_sec < y.tv_sec;
+ }
+
+ void
+ XTflash (f)
+ struct frame *f;
+ {
+ BLOCK_INPUT;
+
+ {
+ GC gc;
+
+ /* Create a GC that will use the GXxor function to flip foreground
+ pixels into background pixels. */
+ {
+ XGCValues values;
+
+ values.function = GXxor;
+ values.foreground = (f->output_data.x->foreground_pixel
+ ^ f->output_data.x->background_pixel);
+
+ gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ GCFunction | GCForeground, &values);
+ }
+
+ {
+ /* Get the height not including a menu bar widget. */
+ int height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, FRAME_LINES (f));
+ /* Height of each line to flash. */
+ int flash_height = FRAME_LINE_HEIGHT (f);
+ /* These will be the left and right margins of the rectangles. */
+ int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
+ int flash_right = FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH
(f);
+
+ int width;
+
+ /* Don't flash the area between a scroll bar and the frame
+ edge it is next to. */
+ switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
+ {
+ case vertical_scroll_bar_left:
+ flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
+ break;
+
+ case vertical_scroll_bar_right:
+ flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
+ break;
+
+ default:
+ break;
+ }
+
+ width = flash_right - flash_left;
+
+ /* If window is tall, flash top and bottom line. */
+ if (height > 3 * FRAME_LINE_HEIGHT (f))
+ {
+ XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
+ flash_left,
+ (FRAME_INTERNAL_BORDER_WIDTH (f)
+ + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
+ width, flash_height);
+ XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
+ flash_left,
+ (height - flash_height
+ - FRAME_INTERNAL_BORDER_WIDTH (f)),
+ width, flash_height);
+ }
+ else
+ /* If it is short, flash it all. */
+ XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
+ flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
+ width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
+
+ x_flush (f);
+
+ {
+ struct timeval wakeup;
+
+ EMACS_GET_TIME (wakeup);
+
+ /* Compute time to wait until, propagating carry from usecs. */
+ wakeup.tv_usec += 150000;
+ wakeup.tv_sec += (wakeup.tv_usec / 1000000);
+ wakeup.tv_usec %= 1000000;
+
+ /* Keep waiting until past the time wakeup or any input gets
+ available. */
+ while (! detect_input_pending ())
+ {
+ struct timeval current;
+ struct timeval timeout;
+
+ EMACS_GET_TIME (current);
+
+ /* Break if result would be negative. */
+ if (timeval_subtract (¤t, wakeup, current))
+ break;
+
+ /* How long `select' should wait. */
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 10000;
+
+ /* Try to wait that long--but we might wake up sooner. */
+ select (0, NULL, NULL, NULL, &timeout);
+ }
+ }
+
+ /* If window is tall, flash top and bottom line. */
+ if (height > 3 * FRAME_LINE_HEIGHT (f))
+ {
+ XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
+ flash_left,
+ (FRAME_INTERNAL_BORDER_WIDTH (f)
+ + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
+ width, flash_height);
+ XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
+ flash_left,
+ (height - flash_height
+ - FRAME_INTERNAL_BORDER_WIDTH (f)),
+ width, flash_height);
+ }
+ else
+ /* If it is short, flash it all. */
+ XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
+ flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
+ width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
+
+ XFreeGC (FRAME_X_DISPLAY (f), gc);
+ x_flush (f);
+ }
+ }
+
+ UNBLOCK_INPUT;
+ }
+
+ #endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
+
+
+ /* Make audible bell. */
+
+ void
+ XTring_bell ()
+ {
+ struct frame *f = SELECTED_FRAME ();
+
+ if (FRAME_X_DISPLAY (f))
+ {
+ #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
+ if (visible_bell)
+ XTflash (f);
+ else
+ #endif
+ {
+ BLOCK_INPUT;
+ XBell (FRAME_X_DISPLAY (f), 0);
+ XFlush (FRAME_X_DISPLAY (f));
+ UNBLOCK_INPUT;
+ }
+ }
+ }
+
+
+ /* 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 x_update_begin and x_update_end. */
+
+ static void
+ XTset_terminal_window (n)
+ register int n;
+ {
+ /* This function intentionally left blank. */
+ }
+
+
+
+ /***********************************************************************
+ Line Dance
+ ***********************************************************************/
+
+ /* Perform an insert-lines or delete-lines operation, inserting N
+ lines or deleting -N lines at vertical position VPOS. */
+
+ static void
+ x_ins_del_lines (vpos, n)
+ int vpos, n;
+ {
+ abort ();
+ }
+
+
+ /* Scroll part of the display as described by RUN. */
+
+ static void
+ x_scroll_run (w, run)
+ struct window *w;
+ struct run *run;
+ {
+ struct frame *f = XFRAME (w->frame);
+ int x, y, width, height, from_y, to_y, bottom_y;
+
+ /* Get frame-relative bounding box of the text display area of W,
+ without mode lines. Include in this box the left and right
+ fringe of W. */
+ window_box (w, -1, &x, &y, &width, &height);
+
+ from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
+ to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
+ bottom_y = y + height;
+
+ if (to_y < from_y)
+ {
+ /* Scrolling up. Make sure we don't copy part of the mode
+ line at the bottom. */
+ if (from_y + run->height > bottom_y)
+ height = bottom_y - from_y;
+ else
+ height = run->height;
+ }
+ else
+ {
+ /* Scolling down. Make sure we don't copy over the mode line.
+ at the bottom. */
+ if (to_y + run->height > bottom_y)
+ height = bottom_y - to_y;
+ else
+ height = run->height;
+ }
+
+ BLOCK_INPUT;
+
+ /* Cursor off. Will be switched on again in x_update_window_end. */
+ updated_window = w;
+ x_clear_cursor (w);
+
+ XCopyArea (FRAME_X_DISPLAY (f),
+ FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
+ f->output_data.x->normal_gc,
+ x, from_y,
+ width, height,
+ x, to_y);
+
+ UNBLOCK_INPUT;
+ }
+
+
+
+ /***********************************************************************
+ Exposure Events
+ ***********************************************************************/
+
+
+ static void
+ frame_highlight (f)
+ struct frame *f;
+ {
+ /* We used to only do this if Vx_no_window_manager was non-nil, but
+ the ICCCM (section 4.1.6) says that the window's border pixmap
+ and border pixel are window attributes which are "private to the
+ client", so we can always change it to whatever we want. */
+ BLOCK_INPUT;
+ XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ f->output_data.x->border_pixel);
+ UNBLOCK_INPUT;
+ x_update_cursor (f, 1);
+ }
+
+ static void
+ frame_unhighlight (f)
+ struct frame *f;
+ {
+ /* We used to only do this if Vx_no_window_manager was non-nil, but
+ the ICCCM (section 4.1.6) says that the window's border pixmap
+ and border pixel are window attributes which are "private to the
+ client", so we can always change it to whatever we want. */
+ BLOCK_INPUT;
+ XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ f->output_data.x->border_tile);
+ UNBLOCK_INPUT;
+ x_update_cursor (f, 1);
+ }
+
+ /* The focus has changed. Update the frames as necessary to reflect
+ the new situation. Note that we can't change the selected frame
+ here, because the Lisp code we are interrupting might become confused.
+ Each event gets marked with the frame in which it occurred, so the
+ Lisp code can tell when the switch took place by examining the events. */
+
+ static void
+ x_new_focus_frame (dpyinfo, frame)
+ struct x_display_info *dpyinfo;
+ struct frame *frame;
+ {
+ struct frame *old_focus = dpyinfo->x_focus_frame;
+
+ if (frame != dpyinfo->x_focus_frame)
+ {
+ /* Set this before calling other routines, so that they see
+ the correct value of x_focus_frame. */
+ dpyinfo->x_focus_frame = frame;
+
+ if (old_focus && old_focus->auto_lower)
+ x_lower_frame (old_focus);
+
+ #if 0
+ selected_frame = frame;
+ XSETFRAME (XWINDOW (selected_frame->selected_window)->frame,
+ selected_frame);
+ Fselect_window (selected_frame->selected_window, Qnil);
+ choose_minibuf_frame ();
+ #endif /* ! 0 */
+
+ if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
+ pending_autoraise_frame = dpyinfo->x_focus_frame;
+ else
+ pending_autoraise_frame = 0;
+ }
+
+ x_frame_rehighlight (dpyinfo);
+ }
+
+ /* Handle FocusIn and FocusOut state changes for FRAME.
+ If FRAME has focus and there exists more than one frame, puts
+ a FOCUS_IN_EVENT into BUFP.
+ Returns number of events inserted into BUFP. */
+
+ static int
+ x_focus_changed (type, state, dpyinfo, frame, bufp, numchars)
+ int type;
+ int state;
+ struct x_display_info *dpyinfo;
+ struct frame *frame;
+ struct input_event *bufp;
+ int numchars;
+ {
+ int nr_events = 0;
+
+ if (type == FocusIn)
+ {
+ if (dpyinfo->x_focus_event_frame != frame)
+ {
+ x_new_focus_frame (dpyinfo, frame);
+ dpyinfo->x_focus_event_frame = frame;
+
+ /* Don't stop displaying the initial startup message
+ for a switch-frame event we don't need. */
+ if (numchars > 0
+ && GC_NILP (Vterminal_frame)
+ && GC_CONSP (Vframe_list)
+ && !GC_NILP (XCDR (Vframe_list)))
+ {
+ bufp->kind = FOCUS_IN_EVENT;
+ XSETFRAME (bufp->frame_or_window, frame);
+ bufp->arg = Qnil;
+ ++bufp;
+ numchars--;
+ ++nr_events;
+ }
+ }
+
+ frame->output_data.x->focus_state |= state;
+
+ #ifdef HAVE_X_I18N
+ if (FRAME_XIC (frame))
+ XSetICFocus (FRAME_XIC (frame));
+ #endif
+ }
+ else if (type == FocusOut)
+ {
+ frame->output_data.x->focus_state &= ~state;
+
+ if (dpyinfo->x_focus_event_frame == frame)
+ {
+ dpyinfo->x_focus_event_frame = 0;
+ x_new_focus_frame (dpyinfo, 0);
+ }
+
+ #ifdef HAVE_X_I18N
+ if (FRAME_XIC (frame))
+ XUnsetICFocus (FRAME_XIC (frame));
+ #endif
+ }
+
+ return nr_events;
+ }
+
+ /* The focus may have changed. Figure out if it is a real focus change,
+ by checking both FocusIn/Out and Enter/LeaveNotify events.
+
+ Returns number of events inserted into BUFP. */
+
+ static int
+ x_detect_focus_change (dpyinfo, event, bufp, numchars)
+ struct x_display_info *dpyinfo;
+ XEvent *event;
+ struct input_event *bufp;
+ int numchars;
+ {
+ struct frame *frame;
+ int nr_events = 0;
+
+ frame = x_any_window_to_frame (dpyinfo, event->xany.window);
+ if (! frame) return nr_events;
+
+ switch (event->type)
+ {
+ case EnterNotify:
+ case LeaveNotify:
+ if (event->xcrossing.detail != NotifyInferior
+ && event->xcrossing.focus
+ && ! (frame->output_data.x->focus_state & FOCUS_EXPLICIT))
+ nr_events = x_focus_changed ((event->type == EnterNotify
+ ? FocusIn : FocusOut),
+ FOCUS_IMPLICIT,
+ dpyinfo,
+ frame,
+ bufp,
+ numchars);
+ break;
+
+ case FocusIn:
+ case FocusOut:
+ nr_events = x_focus_changed (event->type,
+ (event->xfocus.detail == NotifyPointer
+ ? FOCUS_IMPLICIT : FOCUS_EXPLICIT),
+ dpyinfo,
+ frame,
+ bufp,
+ numchars);
+ break;
+ }
+
+ return nr_events;
+ }
+
+
+ /* Handle an event saying the mouse has moved out of an Emacs frame. */
+
+ void
+ x_mouse_leave (dpyinfo)
+ struct x_display_info *dpyinfo;
+ {
+ x_new_focus_frame (dpyinfo, dpyinfo->x_focus_event_frame);
+ }
+
+ /* The focus has changed, or we have redirected a frame's focus to
+ another frame (this happens when a frame uses a surrogate
+ mini-buffer frame). Shift the highlight as appropriate.
+
+ The FRAME argument doesn't necessarily have anything to do with which
+ frame is being highlighted or un-highlighted; we only use it to find
+ the appropriate X display info. */
+
+ static void
+ XTframe_rehighlight (frame)
+ struct frame *frame;
+ {
+ x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame));
+ }
+
+ static void
+ x_frame_rehighlight (dpyinfo)
+ struct x_display_info *dpyinfo;
+ {
+ struct frame *old_highlight = dpyinfo->x_highlight_frame;
+
+ if (dpyinfo->x_focus_frame)
+ {
+ dpyinfo->x_highlight_frame
+ = ((GC_FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
+ ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
+ : dpyinfo->x_focus_frame);
+ if (! FRAME_LIVE_P (dpyinfo->x_highlight_frame))
+ {
+ FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
+ dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
+ }
+ }
+ else
+ dpyinfo->x_highlight_frame = 0;
+
+ if (dpyinfo->x_highlight_frame != old_highlight)
+ {
+ if (old_highlight)
+ frame_unhighlight (old_highlight);
+ if (dpyinfo->x_highlight_frame)
+ frame_highlight (dpyinfo->x_highlight_frame);
+ }
+ }
+
+
+
+ /* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
+
+ /* Initialize mode_switch_bit and modifier_meaning. */
+ static void
+ x_find_modifier_meanings (dpyinfo)
+ struct x_display_info *dpyinfo;
+ {
+ int min_code, max_code;
+ KeySym *syms;
+ int syms_per_code;
+ XModifierKeymap *mods;
+
+ dpyinfo->meta_mod_mask = 0;
+ dpyinfo->shift_lock_mask = 0;
+ dpyinfo->alt_mod_mask = 0;
+ dpyinfo->super_mod_mask = 0;
+ dpyinfo->hyper_mod_mask = 0;
+
+ #ifdef HAVE_X11R4
+ XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
+ #else
+ min_code = dpyinfo->display->min_keycode;
+ max_code = dpyinfo->display->max_keycode;
+ #endif
+
+ syms = XGetKeyboardMapping (dpyinfo->display,
+ min_code, max_code - min_code + 1,
+ &syms_per_code);
+ mods = XGetModifierMapping (dpyinfo->display);
+
+ /* Scan the modifier table to see which modifier bits the Meta and
+ Alt keysyms are on. */
+ {
+ int row, col; /* The row and column in the modifier table. */
+
+ for (row = 3; row < 8; row++)
+ for (col = 0; col < mods->max_keypermod; col++)
+ {
+ KeyCode code
+ = mods->modifiermap[(row * mods->max_keypermod) + col];
+
+ /* Zeroes are used for filler. Skip them. */
+ if (code == 0)
+ continue;
+
+ /* Are any of this keycode's keysyms a meta key? */
+ {
+ int code_col;
+
+ for (code_col = 0; code_col < syms_per_code; code_col++)
+ {
+ int sym = syms[((code - min_code) * syms_per_code) + code_col];
+
+ switch (sym)
+ {
+ case XK_Meta_L:
+ case XK_Meta_R:
+ dpyinfo->meta_mod_mask |= (1 << row);
+ break;
+
+ case XK_Alt_L:
+ case XK_Alt_R:
+ dpyinfo->alt_mod_mask |= (1 << row);
+ break;
+
+ case XK_Hyper_L:
+ case XK_Hyper_R:
+ dpyinfo->hyper_mod_mask |= (1 << row);
+ break;
+
+ case XK_Super_L:
+ case XK_Super_R:
+ dpyinfo->super_mod_mask |= (1 << row);
+ break;
+
+ case XK_Shift_Lock:
+ /* Ignore this if it's not on the lock modifier. */
+ if ((1 << row) == LockMask)
+ dpyinfo->shift_lock_mask = LockMask;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* If we couldn't find any meta keys, accept any alt keys as meta keys. */
+ if (! dpyinfo->meta_mod_mask)
+ {
+ dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask;
+ dpyinfo->alt_mod_mask = 0;
+ }
+
+ /* If some keys are both alt and meta,
+ make them just meta, not alt. */
+ if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask)
+ {
+ dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask;
+ }
+
+ XFree ((char *) syms);
+ XFreeModifiermap (mods);
+ }
+
+ /* Convert between the modifier bits X uses and the modifier bits
+ Emacs uses. */
+
+ static unsigned int
+ x_x_to_emacs_modifiers (dpyinfo, state)
+ struct x_display_info *dpyinfo;
+ unsigned int state;
+ {
+ EMACS_UINT mod_meta = meta_modifier;
+ EMACS_UINT mod_alt = alt_modifier;
+ EMACS_UINT mod_hyper = hyper_modifier;
+ EMACS_UINT mod_super = super_modifier;
+ Lisp_Object tem;
+
+ tem = Fget (Vx_alt_keysym, Qmodifier_value);
+ if (! EQ (tem, Qnil)) mod_alt = XUINT (tem);
+ tem = Fget (Vx_meta_keysym, Qmodifier_value);
+ if (! EQ (tem, Qnil)) mod_meta = XUINT (tem);
+ tem = Fget (Vx_hyper_keysym, Qmodifier_value);
+ if (! EQ (tem, Qnil)) mod_hyper = XUINT (tem);
+ tem = Fget (Vx_super_keysym, Qmodifier_value);
+ if (! EQ (tem, Qnil)) mod_super = XUINT (tem);
+
+
+ return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ?
shift_modifier : 0)
+ | ((state & ControlMask) ? ctrl_modifier : 0)
+ | ((state & dpyinfo->meta_mod_mask) ? mod_meta
: 0)
+ | ((state & dpyinfo->alt_mod_mask) ? mod_alt
: 0)
+ | ((state & dpyinfo->super_mod_mask) ? mod_super : 0)
+ | ((state & dpyinfo->hyper_mod_mask) ? mod_hyper : 0));
+ }
+
+ static unsigned int
+ x_emacs_to_x_modifiers (dpyinfo, state)
+ struct x_display_info *dpyinfo;
+ unsigned int state;
+ {
+ EMACS_UINT mod_meta = meta_modifier;
+ EMACS_UINT mod_alt = alt_modifier;
+ EMACS_UINT mod_hyper = hyper_modifier;
+ EMACS_UINT mod_super = super_modifier;
+
+ Lisp_Object tem;
+
+ tem = Fget (Vx_alt_keysym, Qmodifier_value);
+ if (! EQ (tem, Qnil)) mod_alt = XUINT (tem);
+ tem = Fget (Vx_meta_keysym, Qmodifier_value);
+ if (! EQ (tem, Qnil)) mod_meta = XUINT (tem);
+ tem = Fget (Vx_hyper_keysym, Qmodifier_value);
+ if (! EQ (tem, Qnil)) mod_hyper = XUINT (tem);
+ tem = Fget (Vx_super_keysym, Qmodifier_value);
+ if (! EQ (tem, Qnil)) mod_super = XUINT (tem);
+
+
+ return ( ((state & mod_alt) ? dpyinfo->alt_mod_mask : 0)
+ | ((state & mod_super) ? dpyinfo->super_mod_mask : 0)
+ | ((state & mod_hyper) ? dpyinfo->hyper_mod_mask : 0)
+ | ((state & shift_modifier) ? ShiftMask : 0)
+ | ((state & ctrl_modifier) ? ControlMask : 0)
+ | ((state & mod_meta) ? dpyinfo->meta_mod_mask : 0));
+ }
+
+ /* Convert a keysym to its name. */
+
+ char *
+ x_get_keysym_name (keysym)
+ KeySym keysym;
+ {
+ char *value;
+
+ BLOCK_INPUT;
+ value = XKeysymToString (keysym);
+ UNBLOCK_INPUT;
+
+ return value;
+ }
+
+
+
+ /* Mouse clicks and mouse movement. Rah. */
+
+ /* 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. */
+
+ static Lisp_Object
+ construct_mouse_click (result, event, f)
+ struct input_event *result;
+ XButtonEvent *event;
+ struct frame *f;
+ {
+ /* Make the event type NO_EVENT; we'll change that when we decide
+ otherwise. */
+ result->kind = MOUSE_CLICK_EVENT;
+ result->code = event->button - Button1;
+ result->timestamp = event->time;
+ result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
+ event->state)
+ | (event->type == ButtonRelease
+ ? up_modifier
+ : down_modifier));
+
+ XSETINT (result->x, event->x);
+ XSETINT (result->y, event->y);
+ XSETFRAME (result->frame_or_window, f);
+ result->arg = Qnil;
+ return Qnil;
+ }
+
+
+ /* Function to report a mouse movement to the mainstream Emacs code.
+ The input handler calls this.
+
+ We have received a mouse movement event, which is given in *event.
+ If the mouse is over a different glyph than it was last time, tell
+ the mainstream emacs code by setting mouse_moved. If not, ask for
+ another motion event, so we can check again the next time it moves. */
+
+ static XMotionEvent last_mouse_motion_event;
+ static Lisp_Object last_mouse_motion_frame;
+
+ static void
+ note_mouse_movement (frame, event)
+ FRAME_PTR frame;
+ XMotionEvent *event;
+ {
+ last_mouse_movement_time = event->time;
+ last_mouse_motion_event = *event;
+ XSETFRAME (last_mouse_motion_frame, frame);
+
+ if (event->window != FRAME_X_WINDOW (frame))
+ {
+ frame->mouse_moved = 1;
+ last_mouse_scroll_bar = Qnil;
+ note_mouse_highlight (frame, -1, -1);
+ }
+
+ /* Has the mouse moved off the glyph it was on at the last sighting? */
+ else if (event->x < last_mouse_glyph.x
+ || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
+ || event->y < last_mouse_glyph.y
+ || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
+ {
+ frame->mouse_moved = 1;
+ last_mouse_scroll_bar = Qnil;
+ note_mouse_highlight (frame, event->x, event->y);
+ }
+ }
+
+
+ /************************************************************************
+ Mouse Face
+ ************************************************************************/
+
+ static void
+ redo_mouse_highlight ()
+ {
+ if (!NILP (last_mouse_motion_frame)
+ && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
+ note_mouse_highlight (XFRAME (last_mouse_motion_frame),
+ last_mouse_motion_event.x,
+ last_mouse_motion_event.y);
+ }
+
+
+ static int glyph_rect P_ ((struct frame *f, int, int, XRectangle *));
+
+
+ /* Try to determine frame pixel position and size of the glyph under
+ frame pixel coordinates X/Y on frame F . Return the position and
+ size in *RECT. Value is non-zero if we could compute these
+ values. */
+
+ static int
+ glyph_rect (f, x, y, rect)
+ struct frame *f;
+ int x, y;
+ XRectangle *rect;
+ {
+ Lisp_Object window;
+ int found = 0;
+
+ window = window_from_coordinates (f, x, y, 0, &x, &y, 0);
+ if (!NILP (window))
+ {
+ struct window *w = XWINDOW (window);
+ struct glyph_row *r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+ struct glyph_row *end = r + w->current_matrix->nrows - 1;
+
+ for (; !found && r < end && r->enabled_p; ++r)
+ if (r->y >= y)
+ {
+ struct glyph *g = r->glyphs[TEXT_AREA];
+ struct glyph *end = g + r->used[TEXT_AREA];
+ int gx;
+
+ for (gx = r->x; !found && g < end; gx += g->pixel_width, ++g)
+ if (gx >= x)
+ {
+ rect->width = g->pixel_width;
+ rect->height = r->height;
+ rect->x = WINDOW_TO_FRAME_PIXEL_X (w, gx);
+ rect->y = WINDOW_TO_FRAME_PIXEL_Y (w, r->y);
+ found = 1;
+ }
+ }
+ }
+
+ return found;
+ }
+
+
+ /* Return the current position of the mouse.
+ *FP should be a frame which indicates which display to ask about.
+
+ If the mouse movement started in a scroll bar, set *FP, *BAR_WINDOW,
+ and *PART to the frame, window, and scroll bar part that the mouse
+ is over. Set *X and *Y to the portion and whole of the mouse's
+ position on the scroll bar.
+
+ If the mouse movement started elsewhere, set *FP to the frame the
+ mouse is on, *BAR_WINDOW to nil, and *X and *Y to the character cell
+ the mouse is over.
+
+ Set *TIME to the server time-stamp for the time at which the mouse
+ was at this position.
+
+ Don't store anything if we don't have a valid set of values to report.
+
+ This clears the mouse_moved flag, so we can wait for the next mouse
+ movement. */
+
+ static void
+ XTmouse_position (fp, insist, bar_window, part, x, y, time)
+ FRAME_PTR *fp;
+ int insist;
+ Lisp_Object *bar_window;
+ enum scroll_bar_part *part;
+ Lisp_Object *x, *y;
+ unsigned long *time;
+ {
+ FRAME_PTR f1;
+
+ BLOCK_INPUT;
+
+ if (! NILP (last_mouse_scroll_bar) && insist == 0)
+ x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
+ else
+ {
+ Window root;
+ int root_x, root_y;
+
+ Window dummy_window;
+ int dummy;
+
+ Lisp_Object frame, tail;
+
+ /* Clear the mouse-moved flag for every frame on this display. */
+ FOR_EACH_FRAME (tail, frame)
+ if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
+ XFRAME (frame)->mouse_moved = 0;
+
+ last_mouse_scroll_bar = Qnil;
+
+ /* Figure out which root window we're on. */
+ XQueryPointer (FRAME_X_DISPLAY (*fp),
+ DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
+
+ /* The root window which contains the pointer. */
+ &root,
+
+ /* Trash which we can't trust if the pointer is on
+ a different screen. */
+ &dummy_window,
+
+ /* The position on that root window. */
+ &root_x, &root_y,
+
+ /* More trash we can't trust. */
+ &dummy, &dummy,
+
+ /* Modifier keys and pointer buttons, about which
+ we don't care. */
+ (unsigned int *) &dummy);
+
+ /* Now we have a position on the root; find the innermost window
+ containing the pointer. */
+ {
+ Window win, child;
+ int win_x, win_y;
+ int parent_x = 0, parent_y = 0;
+ int count;
+
+ win = root;
+
+ /* XTranslateCoordinates can get errors if the window
+ structure is changing at the same time this function
+ is running. So at least we must not crash from them. */
+
+ count = x_catch_errors (FRAME_X_DISPLAY (*fp));
+
+ if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
+ && FRAME_LIVE_P (last_mouse_frame))
+ {
+ /* If mouse was grabbed on a frame, give coords for that frame
+ even if the mouse is now outside it. */
+ XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
+
+ /* From-window, to-window. */
+ root, FRAME_X_WINDOW (last_mouse_frame),
+
+ /* From-position, to-position. */
+ root_x, root_y, &win_x, &win_y,
+
+ /* Child of win. */
+ &child);
+ f1 = last_mouse_frame;
+ }
+ else
+ {
+ while (1)
+ {
+ XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
+
+ /* From-window, to-window. */
+ root, win,
+
+ /* From-position, to-position. */
+ root_x, root_y, &win_x, &win_y,
+
+ /* Child of win. */
+ &child);
+
+ if (child == None || child == win)
+ break;
+
+ win = child;
+ parent_x = win_x;
+ parent_y = win_y;
+ }
+
+ /* Now we know that:
+ win is the innermost window containing the pointer
+ (XTC says it has no child containing the pointer),
+ win_x and win_y are the pointer's position in it
+ (XTC did this the last time through), and
+ parent_x and parent_y are the pointer's position in win's parent.
+ (They are what win_x and win_y were when win was child.
+ If win is the root window, it has no parent, and
+ parent_{x,y} are invalid, but that's okay, because we'll
+ never use them in that case.) */
+
+ /* Is win one of our frames? */
+ f1 = x_any_window_to_frame (FRAME_X_DISPLAY_INFO (*fp), win);
+
+ #ifdef USE_X_TOOLKIT
+ /* If we end up with the menu bar window, say it's not
+ on the frame. */
+ if (f1 != NULL
+ && f1->output_data.x->menubar_widget
+ && win == XtWindow (f1->output_data.x->menubar_widget))
+ f1 = NULL;
+ #endif /* USE_X_TOOLKIT */
+ }
+
+ if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
+ f1 = 0;
+
+ x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
+
+ /* If not, is it one of our scroll bars? */
+ if (! f1)
+ {
+ struct scroll_bar *bar = x_window_to_scroll_bar (win);
+
+ if (bar)
+ {
+ f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+ win_x = parent_x;
+ win_y = parent_y;
+ }
+ }
+
+ if (f1 == 0 && insist > 0)
+ f1 = SELECTED_FRAME ();
+
+ if (f1)
+ {
+ /* Ok, we found a frame. Store all the values.
+ last_mouse_glyph is a rectangle used to reduce the
+ generation of mouse events. To not miss any motion
+ events, we must divide the frame into rectangles of the
+ size of the smallest character that could be displayed
+ on it, i.e. into the same rectangles that matrices on
+ the frame are divided into. */
+
+ int width, height, gx, gy;
+ XRectangle rect;
+
+ if (glyph_rect (f1, win_x, win_y, &rect))
+ last_mouse_glyph = rect;
+ else
+ {
+ width = FRAME_SMALLEST_CHAR_WIDTH (f1);
+ height = FRAME_SMALLEST_FONT_HEIGHT (f1);
+ gx = win_x;
+ gy = win_y;
+
+ /* Arrange for the division in FRAME_PIXEL_X_TO_COL etc. to
+ round down even for negative values. */
+ if (gx < 0)
+ gx -= width - 1;
+ if (gy < 0)
+ gy -= height - 1;
+ gx = (gx + width - 1) / width * width;
+ gy = (gy + height - 1) / height * height;
+
+ last_mouse_glyph.width = width;
+ last_mouse_glyph.height = height;
+ last_mouse_glyph.x = gx;
+ last_mouse_glyph.y = gy;
+ }
+
+ *bar_window = Qnil;
+ *part = 0;
+ *fp = f1;
+ XSETINT (*x, win_x);
+ XSETINT (*y, win_y);
+ *time = last_mouse_movement_time;
+ }
+ }
+ }
+
+ UNBLOCK_INPUT;
+ }
+
+
+
+ /***********************************************************************
+ Scroll bars
+ ***********************************************************************/
+
+ /* Scroll bar support. */
+
+ /* Given an X window ID, find the struct scroll_bar which manages it.
+ This can be called in GC, so we have to make sure to strip off mark
+ bits. */
+
+ static struct scroll_bar *
+ x_window_to_scroll_bar (window_id)
+ Window window_id;
+ {
+ Lisp_Object tail;
+
+ #ifdef USE_GTK
+ window_id = (Window) xg_get_scroll_id_for_window (window_id);
+ #endif /* USE_GTK */
+
+ for (tail = Vframe_list;
+ XGCTYPE (tail) == Lisp_Cons;
+ tail = XCDR (tail))
+ {
+ Lisp_Object frame, bar, condemned;
+
+ frame = XCAR (tail);
+ /* All elements of Vframe_list should be frames. */
+ if (! GC_FRAMEP (frame))
+ abort ();
+
+ /* Scan this frame's scroll bar list for a scroll bar with the
+ right window ID. */
+ condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
+ for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
+ /* This trick allows us to search both the ordinary and
+ condemned scroll bar lists with one loop. */
+ ! GC_NILP (bar) || (bar = condemned,
+ condemned = Qnil,
+ ! GC_NILP (bar));
+ bar = XSCROLL_BAR (bar)->next)
+ if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
+ return XSCROLL_BAR (bar);
+ }
+
+ return 0;
+ }
+
+
+ #if defined USE_LUCID
+
+ /* Return the Lucid menu bar WINDOW is part of. Return null
+ if WINDOW is not part of a menu bar. */
+
+ static Widget
+ x_window_to_menu_bar (window)
+ Window window;
+ {
+ Lisp_Object tail;
+
+ for (tail = Vframe_list;
+ XGCTYPE (tail) == Lisp_Cons;
+ tail = XCDR (tail))
+ {
+ Lisp_Object frame = XCAR (tail);
+ Widget menu_bar = XFRAME (frame)->output_data.x->menubar_widget;
+
+ if (menu_bar && xlwmenu_window_p (menu_bar, window))
+ return menu_bar;
+ }
+
+ return NULL;
+ }
+
+ #endif /* USE_LUCID */
+
+
+ /************************************************************************
+ Toolkit scroll bars
+ ************************************************************************/
+
+ #ifdef USE_TOOLKIT_SCROLL_BARS
+
+ static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
+ static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
+ static void x_create_toolkit_scroll_bar P_ ((struct frame *,
+ struct scroll_bar *));
+ static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
+ int, int, int));
+
+
+ /* Lisp window being scrolled. Set when starting to interact with
+ a toolkit scroll bar, reset to nil when ending the interaction. */
+
+ static Lisp_Object window_being_scrolled;
+
+ /* Last scroll bar part sent in xm_scroll_callback. */
+
+ static int last_scroll_bar_part;
+
+ /* Whether this is an Xaw with arrow-scrollbars. This should imply
+ that movements of 1/20 of the screen size are mapped to up/down. */
+
+ #ifndef USE_GTK
+ /* Id of action hook installed for scroll bars. */
+
+ static XtActionHookId action_hook_id;
+
+ static Boolean xaw3d_arrow_scroll;
+
+ /* Whether the drag scrolling maintains the mouse at the top of the
+ thumb. If not, resizing the thumb needs to be done more carefully
+ to avoid jerkyness. */
+
+ static Boolean xaw3d_pick_top;
+
+ extern void set_vertical_scroll_bar P_ ((struct window *));
+
+ /* Action hook installed via XtAppAddActionHook when toolkit scroll
+ bars are used.. The hook is responsible for detecting when
+ the user ends an interaction with the scroll bar, and generates
+ a `end-scroll' SCROLL_BAR_CLICK_EVENT' event if so. */
+
+ static void
+ xt_action_hook (widget, client_data, action_name, event, params,
+ num_params)
+ Widget widget;
+ XtPointer client_data;
+ String action_name;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+ {
+ int scroll_bar_p;
+ char *end_action;
+
+ #ifdef USE_MOTIF
+ scroll_bar_p = XmIsScrollBar (widget);
+ end_action = "Release";
+ #else /* !USE_MOTIF i.e. use Xaw */
+ scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
+ end_action = "EndScroll";
+ #endif /* USE_MOTIF */
+
+ if (scroll_bar_p
+ && strcmp (action_name, end_action) == 0
+ && WINDOWP (window_being_scrolled))
+ {
+ struct window *w;
+
+ x_send_scroll_bar_event (window_being_scrolled,
+ scroll_bar_end_scroll, 0, 0);
+ w = XWINDOW (window_being_scrolled);
+
+ if (!NILP (XSCROLL_BAR (w->vertical_scroll_bar)->dragging))
+ {
+ XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
+ /* The thumb size is incorrect while dragging: fix it. */
+ set_vertical_scroll_bar (w);
+ }
+ window_being_scrolled = Qnil;
+ last_scroll_bar_part = -1;
+
+ /* Xt timeouts no longer needed. */
+ toolkit_scroll_bar_interaction = 0;
+ }
+ }
+ #endif /* not USE_GTK */
+
+ /* A vector of windows used for communication between
+ x_send_scroll_bar_event and x_scroll_bar_to_input_event. */
+
+ static struct window **scroll_bar_windows;
+ static int scroll_bar_windows_size;
+
+
+ /* Send a client message with message type Xatom_Scrollbar for a
+ scroll action to the frame of WINDOW. PART is a value identifying
+ the part of the scroll bar that was clicked on. PORTION is the
+ amount to scroll of a whole of WHOLE. */
+
+ static void
+ x_send_scroll_bar_event (window, part, portion, whole)
+ Lisp_Object window;
+ int part, portion, whole;
+ {
+ XEvent event;
+ XClientMessageEvent *ev = (XClientMessageEvent *) &event;
+ struct window *w = XWINDOW (window);
+ struct frame *f = XFRAME (w->frame);
+ int i;
+
+ BLOCK_INPUT;
+
+ /* Construct a ClientMessage event to send to the frame. */
+ ev->type = ClientMessage;
+ ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
+ ev->display = FRAME_X_DISPLAY (f);
+ ev->window = FRAME_X_WINDOW (f);
+ ev->format = 32;
+
+ /* We can only transfer 32 bits in the XClientMessageEvent, which is
+ not enough to store a pointer or Lisp_Object on a 64 bit system.
+ So, store the window in scroll_bar_windows and pass the index
+ into that array in the event. */
+ for (i = 0; i < scroll_bar_windows_size; ++i)
+ if (scroll_bar_windows[i] == NULL)
+ break;
+
+ if (i == scroll_bar_windows_size)
+ {
+ int new_size = max (10, 2 * scroll_bar_windows_size);
+ size_t nbytes = new_size * sizeof *scroll_bar_windows;
+ size_t old_nbytes = scroll_bar_windows_size * sizeof
*scroll_bar_windows;
+
+ scroll_bar_windows = (struct window **) xrealloc (scroll_bar_windows,
+ nbytes);
+ bzero (&scroll_bar_windows[i], nbytes - old_nbytes);
+ scroll_bar_windows_size = new_size;
+ }
+
+ scroll_bar_windows[i] = w;
+ ev->data.l[0] = (long) i;
+ ev->data.l[1] = (long) part;
+ ev->data.l[2] = (long) 0;
+ ev->data.l[3] = (long) portion;
+ ev->data.l[4] = (long) whole;
+
+ /* Make Xt timeouts work while the scroll bar is active. */
+ toolkit_scroll_bar_interaction = 1;
+
+ /* Setting the event mask to zero means that the message will
+ be sent to the client that created the window, and if that
+ window no longer exists, no event will be sent. */
+ XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
+ UNBLOCK_INPUT;
+ }
+
+
+ /* Transform a scroll bar ClientMessage EVENT to an Emacs input event
+ in *IEVENT. */
+
+ static void
+ x_scroll_bar_to_input_event (event, ievent)
+ XEvent *event;
+ struct input_event *ievent;
+ {
+ XClientMessageEvent *ev = (XClientMessageEvent *) event;
+ Lisp_Object window;
+ struct frame *f;
+ struct window *w;
+
+ w = scroll_bar_windows[ev->data.l[0]];
+ scroll_bar_windows[ev->data.l[0]] = NULL;
+
+ XSETWINDOW (window, w);
+ f = XFRAME (w->frame);
+
+ ievent->kind = SCROLL_BAR_CLICK_EVENT;
+ ievent->frame_or_window = window;
+ ievent->arg = Qnil;
+ #ifdef USE_GTK
+ ievent->timestamp = CurrentTime;
+ #else
+ ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
+ #endif
+ ievent->part = ev->data.l[1];
+ ievent->code = ev->data.l[2];
+ ievent->x = make_number ((int) ev->data.l[3]);
+ ievent->y = make_number ((int) ev->data.l[4]);
+ ievent->modifiers = 0;
+ }
+
+
+ #ifdef USE_MOTIF
+
+ /* Minimum and maximum values used for Motif scroll bars. */
+
+ #define XM_SB_MAX 10000000
+
+
+ /* Scroll bar callback for Motif scroll bars. WIDGET is the scroll
+ bar widget. CLIENT_DATA is a pointer to the scroll_bar structure.
+ CALL_DATA is a pointer to a XmScrollBarCallbackStruct. */
+
+ static void
+ xm_scroll_callback (widget, client_data, call_data)
+ Widget widget;
+ XtPointer client_data, call_data;
+ {
+ struct scroll_bar *bar = (struct scroll_bar *) client_data;
+ XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
+ int part = -1, whole = 0, portion = 0;
+
+ switch (cs->reason)
+ {
+ case XmCR_DECREMENT:
+ bar->dragging = Qnil;
+ part = scroll_bar_up_arrow;
+ break;
+
+ case XmCR_INCREMENT:
+ bar->dragging = Qnil;
+ part = scroll_bar_down_arrow;
+ break;
+
+ case XmCR_PAGE_DECREMENT:
+ bar->dragging = Qnil;
+ part = scroll_bar_above_handle;
+ break;
+
+ case XmCR_PAGE_INCREMENT:
+ bar->dragging = Qnil;
+ part = scroll_bar_below_handle;
+ break;
+
+ case XmCR_TO_TOP:
+ bar->dragging = Qnil;
+ part = scroll_bar_to_top;
+ break;
+
+ case XmCR_TO_BOTTOM:
+ bar->dragging = Qnil;
+ part = scroll_bar_to_bottom;
+ break;
+
+ case XmCR_DRAG:
+ {
+ int slider_size;
+
+ /* Get the slider size. */
+ BLOCK_INPUT;
+ XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
+ UNBLOCK_INPUT;
+
+ whole = XM_SB_MAX - slider_size;
+ portion = min (cs->value, whole);
+ part = scroll_bar_handle;
+ bar->dragging = make_number (cs->value);
+ }
+ break;
+
+ case XmCR_VALUE_CHANGED:
+ break;
+ };
+
+ if (part >= 0)
+ {
+ window_being_scrolled = bar->window;
+ last_scroll_bar_part = part;
+ x_send_scroll_bar_event (bar->window, part, portion, whole);
+ }
+ }
+
+
+ #else /* !USE_MOTIF, i.e. Xaw or GTK */
+ #ifdef USE_GTK
+ /* Scroll bar callback for GTK scroll bars. WIDGET is the scroll
+ bar widget. DATA is a pointer to the scroll_bar structure. */
+
+ static void
+ xg_scroll_callback (widget, data)
+ GtkRange *widget;
+ gpointer data;
+ {
+ struct scroll_bar *bar = (struct scroll_bar *) data;
+ gdouble previous;
+ gdouble position;
+ gdouble *p;
+ int diff;
+
+ int part = -1, whole = 0, portion = 0;
+ GtkAdjustment *adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (widget));
+
+ if (xg_ignore_gtk_scrollbar) return;
+
+ position = gtk_adjustment_get_value (adj);
+
+ p = g_object_get_data (G_OBJECT (widget), XG_LAST_SB_DATA);
+ if (! p)
+ {
+ p = (gdouble*) xmalloc (sizeof (gdouble));
+ *p = XG_SB_MIN;
+ g_object_set_data (G_OBJECT (widget), XG_LAST_SB_DATA, p);
+ }
+
+ previous = *p;
+ *p = position;
+
+ diff = (int) (position - previous);
+
+ if (diff == (int) adj->step_increment)
+ {
+ part = scroll_bar_down_arrow;
+ bar->dragging = Qnil;
+ }
+ else if (-diff == (int) adj->step_increment)
+ {
+ part = scroll_bar_up_arrow;
+ bar->dragging = Qnil;
+ }
+ else if (diff == (int) adj->page_increment)
+ {
+ part = scroll_bar_below_handle;
+ bar->dragging = Qnil;
+ }
+ else if (-diff == (int) adj->page_increment)
+ {
+ part = scroll_bar_above_handle;
+ bar->dragging = Qnil;
+ }
+ else
+ {
+ part = scroll_bar_handle;
+ whole = adj->upper - adj->page_size;
+ portion = min ((int)position, whole);
+ bar->dragging = make_number ((int)portion);
+ }
+
+ if (part >= 0)
+ {
+ window_being_scrolled = bar->window;
+ last_scroll_bar_part = part;
+ x_send_scroll_bar_event (bar->window, part, portion, whole);
+ }
+ }
+
+ #else /* not USE_GTK */
+
+ /* Xaw scroll bar callback. Invoked when the thumb is dragged.
+ WIDGET is the scroll bar widget. CLIENT_DATA is a pointer to the
+ scroll bar struct. CALL_DATA is a pointer to a float saying where
+ the thumb is. */
+
+ static void
+ xaw_jump_callback (widget, client_data, call_data)
+ Widget widget;
+ XtPointer client_data, call_data;
+ {
+ struct scroll_bar *bar = (struct scroll_bar *) client_data;
+ float top = *(float *) call_data;
+ float shown;
+ int whole, portion, height;
+ int part;
+
+ /* Get the size of the thumb, a value between 0 and 1. */
+ BLOCK_INPUT;
+ XtVaGetValues (widget, XtNshown, &shown, XtNheight, &height, NULL);
+ UNBLOCK_INPUT;
+
+ whole = 10000000;
+ portion = shown < 1 ? top * whole : 0;
+
+ if (shown < 1 && (abs (top + shown - 1) < 1.0/height))
+ /* Some derivatives of Xaw refuse to shrink the thumb when you reach
+ the bottom, so we force the scrolling whenever we see that we're
+ too close to the bottom (in x_set_toolkit_scroll_bar_thumb
+ we try to ensure that we always stay two pixels away from the
+ bottom). */
+ part = scroll_bar_down_arrow;
+ else
+ part = scroll_bar_handle;
+
+ window_being_scrolled = bar->window;
+ bar->dragging = make_number (portion);
+ last_scroll_bar_part = part;
+ x_send_scroll_bar_event (bar->window, part, portion, whole);
+ }
+
+
+ /* Xaw scroll bar callback. Invoked for incremental scrolling.,
+ i.e. line or page up or down. WIDGET is the Xaw scroll bar
+ widget. CLIENT_DATA is a pointer to the scroll_bar structure for
+ the scroll bar. CALL_DATA is an integer specifying the action that
+ has taken place. Its magnitude is in the range 0..height of the
+ scroll bar. Negative values mean scroll towards buffer start.
+ Values < height of scroll bar mean line-wise movement. */
+
+ static void
+ xaw_scroll_callback (widget, client_data, call_data)
+ Widget widget;
+ XtPointer client_data, call_data;
+ {
+ struct scroll_bar *bar = (struct scroll_bar *) client_data;
+ /* The position really is stored cast to a pointer. */
+ int position = (long) call_data;
+ Dimension height;
+ int part;
+
+ /* Get the height of the scroll bar. */
+ BLOCK_INPUT;
+ XtVaGetValues (widget, XtNheight, &height, NULL);
+ UNBLOCK_INPUT;
+
+ if (abs (position) >= height)
+ part = (position < 0) ? scroll_bar_above_handle : scroll_bar_below_handle;
+
+ /* If Xaw3d was compiled with ARROW_SCROLLBAR,
+ it maps line-movement to call_data = max(5, height/20). */
+ else if (xaw3d_arrow_scroll && abs (position) <= max (5, height / 20))
+ part = (position < 0) ? scroll_bar_up_arrow : scroll_bar_down_arrow;
+ else
+ part = scroll_bar_move_ratio;
+
+ window_being_scrolled = bar->window;
+ bar->dragging = Qnil;
+ last_scroll_bar_part = part;
+ x_send_scroll_bar_event (bar->window, part, position, height);
+ }
+
+ #endif /* not USE_GTK */
+ #endif /* not USE_MOTIF */
+
+ #define SCROLL_BAR_NAME "verticalScrollBar"
+
+ /* Create the widget for scroll bar BAR on frame F. Record the widget
+ and X window of the scroll bar in BAR. */
+
+ #ifdef USE_GTK
+ static void
+ x_create_toolkit_scroll_bar (f, bar)
+ struct frame *f;
+ struct scroll_bar *bar;
+ {
+ char *scroll_bar_name = SCROLL_BAR_NAME;
+
+ BLOCK_INPUT;
+ xg_create_scroll_bar (f, bar, G_CALLBACK (xg_scroll_callback),
+ scroll_bar_name);
+ UNBLOCK_INPUT;
+ }
+
+ #else /* not USE_GTK */
+
+ static void
+ x_create_toolkit_scroll_bar (f, bar)
+ struct frame *f;
+ struct scroll_bar *bar;
+ {
+ Window xwindow;
+ Widget widget;
+ Arg av[20];
+ int ac = 0;
+ char *scroll_bar_name = SCROLL_BAR_NAME;
+ unsigned long pixel;
+
+ BLOCK_INPUT;
+
+ #ifdef USE_MOTIF
+ /* Set resources. Create the widget. */
+ XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
+ XtSetArg (av[ac], XmNminimum, 0); ++ac;
+ XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
+ XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
+ XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
+ XtSetArg (av[ac], XmNincrement, 1); ++ac;
+ XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
+
+ pixel = f->output_data.x->scroll_bar_foreground_pixel;
+ if (pixel != -1)
+ {
+ XtSetArg (av[ac], XmNforeground, pixel);
+ ++ac;
+ }
+
+ pixel = f->output_data.x->scroll_bar_background_pixel;
+ if (pixel != -1)
+ {
+ XtSetArg (av[ac], XmNbackground, pixel);
+ ++ac;
+ }
+
+ widget = XmCreateScrollBar (f->output_data.x->edit_widget,
+ scroll_bar_name, av, ac);
+
+ /* Add one callback for everything that can happen. */
+ XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
+ (XtPointer) bar);
+ XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
+ (XtPointer) bar);
+ XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
+ (XtPointer) bar);
+ XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
+ (XtPointer) bar);
+ XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
+ (XtPointer) bar);
+ XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
+ (XtPointer) bar);
+ XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
+ (XtPointer) bar);
+
+ /* Realize the widget. Only after that is the X window created. */
+ XtRealizeWidget (widget);
+
+ /* Set the cursor to an arrow. I didn't find a resource to do that.
+ And I'm wondering why it hasn't an arrow cursor by default. */
+ XDefineCursor (XtDisplay (widget), XtWindow (widget),
+ f->output_data.x->nontext_cursor);
+
+ #else /* !USE_MOTIF i.e. use Xaw */
+
+ /* Set resources. Create the widget. The background of the
+ Xaw3d scroll bar widget is a little bit light for my taste.
+ We don't alter it here to let users change it according
+ to their taste with `emacs*verticalScrollBar.background: xxx'. */
+ XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
+ XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
+ /* For smoother scrolling with Xaw3d -sm */
+ /* XtSetArg (av[ac], XtNpickTop, True); ++ac; */
+
+ pixel = f->output_data.x->scroll_bar_foreground_pixel;
+ if (pixel != -1)
+ {
+ XtSetArg (av[ac], XtNforeground, pixel);
+ ++ac;
+ }
+
+ pixel = f->output_data.x->scroll_bar_background_pixel;
+ if (pixel != -1)
+ {
+ XtSetArg (av[ac], XtNbackground, pixel);
+ ++ac;
+ }
+
+ /* Top/bottom shadow colors. */
+
+ /* Allocate them, if necessary. */
+ if (f->output_data.x->scroll_bar_top_shadow_pixel == -1)
+ {
+ pixel = f->output_data.x->scroll_bar_background_pixel;
+ if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP
(f),
+ &pixel, 1.2, 0x8000))
+ pixel = -1;
+ f->output_data.x->scroll_bar_top_shadow_pixel = pixel;
+ }
+ if (f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
+ {
+ pixel = f->output_data.x->scroll_bar_background_pixel;
+ if (!x_alloc_lighter_color (f, FRAME_X_DISPLAY (f), FRAME_X_COLORMAP
(f),
+ &pixel, 0.6, 0x4000))
+ pixel = -1;
+ f->output_data.x->scroll_bar_bottom_shadow_pixel = pixel;
+ }
+
+ /* Tell the toolkit about them. */
+ if (f->output_data.x->scroll_bar_top_shadow_pixel == -1
+ || f->output_data.x->scroll_bar_bottom_shadow_pixel == -1)
+ /* We tried to allocate a color for the top/bottom shadow, and
+ failed, so tell Xaw3d to use dithering instead. */
+ {
+ XtSetArg (av[ac], XtNbeNiceToColormap, True);
+ ++ac;
+ }
+ else
+ /* Tell what colors Xaw3d should use for the top/bottom shadow, to
+ be more consistent with other emacs 3d colors, and since Xaw3d is
+ not good at dealing with allocation failure. */
+ {
+ /* This tells Xaw3d to use real colors instead of dithering for
+ the shadows. */
+ XtSetArg (av[ac], XtNbeNiceToColormap, False);
+ ++ac;
+
+ /* Specify the colors. */
+ pixel = f->output_data.x->scroll_bar_top_shadow_pixel;
+ if (pixel != -1)
+ {
+ XtSetArg (av[ac], "topShadowPixel", pixel);
+ ++ac;
+ }
+ pixel = f->output_data.x->scroll_bar_bottom_shadow_pixel;
+ if (pixel != -1)
+ {
+ XtSetArg (av[ac], "bottomShadowPixel", pixel);
+ ++ac;
+ }
+ }
+
+ widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
+ f->output_data.x->edit_widget, av, ac);
+
+ {
+ char *initial = "";
+ char *val = initial;
+ XtVaGetValues (widget, XtNscrollVCursor, (XtPointer) &val,
+ XtNpickTop, (XtPointer) &xaw3d_pick_top, NULL);
+ if (val == initial)
+ { /* ARROW_SCROLL */
+ xaw3d_arrow_scroll = True;
+ /* Isn't that just a personal preference ? -sm */
+ XtVaSetValues (widget, XtNcursorName, "top_left_arrow", NULL);
+ }
+ }
+
+ /* Define callbacks. */
+ XtAddCallback (widget, XtNjumpProc, xaw_jump_callback, (XtPointer) bar);
+ XtAddCallback (widget, XtNscrollProc, xaw_scroll_callback,
+ (XtPointer) bar);
+
+ /* Realize the widget. Only after that is the X window created. */
+ XtRealizeWidget (widget);
+
+ #endif /* !USE_MOTIF */
+
+ /* Install an action hook that lets us detect when the user
+ finishes interacting with a scroll bar. */
+ if (action_hook_id == 0)
+ action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
+
+ /* Remember X window and widget in the scroll bar vector. */
+ SET_SCROLL_BAR_X_WIDGET (bar, widget);
+ xwindow = XtWindow (widget);
+ SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
+
+ UNBLOCK_INPUT;
+ }
+ #endif /* not USE_GTK */
+
+
+ /* Set the thumb size and position of scroll bar BAR. We are currently
+ displaying PORTION out of a whole WHOLE, and our position POSITION. */
+
+ #ifdef USE_GTK
+ static void
+ x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
+ struct scroll_bar *bar;
+ int portion, position, whole;
+ {
+ xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
+ }
+
+ #else /* not USE_GTK */
+ static void
+ x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
+ struct scroll_bar *bar;
+ int portion, position, whole;
+ {
+ struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+ Widget widget = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
+ float top, shown;
+
+ BLOCK_INPUT;
+
+ #ifdef USE_MOTIF
+
+ /* We use an estimate of 30 chars per line rather than the real
+ `portion' value. This has the disadvantage that the thumb size
+ is not very representative, but it makes our life a lot easier.
+ Otherwise, we have to constantly adjust the thumb size, which
+ we can't always do quickly enough: while dragging, the size of
+ the thumb might prevent the user from dragging the thumb all the
+ way to the end. but Motif and some versions of Xaw3d don't allow
+ updating the thumb size while dragging. Also, even if we can update
+ its size, the update will often happen too late.
+ If you don't believe it, check out revision 1.650 of xterm.c to see
+ what hoops we were going through and the still poor behavior we got. */
+ portion = WINDOW_TOTAL_LINES (XWINDOW (bar->window)) * 30;
+ /* When the thumb is at the bottom, position == whole.
+ So we need to increase `whole' to make space for the thumb. */
+ whole += portion;
+
+ if (whole <= 0)
+ top = 0, shown = 1;
+ else
+ {
+ top = (float) position / whole;
+ shown = (float) portion / whole;
+ }
+
+ if (NILP (bar->dragging))
+ {
+ int size, value;
+
+ /* Slider size. Must be in the range [1 .. MAX - MIN] where MAX
+ is the scroll bar's maximum and MIN is the scroll bar's minimum
+ value. */
+ size = shown * XM_SB_MAX;
+ size = min (size, XM_SB_MAX);
+ size = max (size, 1);
+
+ /* Position. Must be in the range [MIN .. MAX - SLIDER_SIZE]. */
+ value = top * XM_SB_MAX;
+ value = min (value, XM_SB_MAX - size);
+
+ XmScrollBarSetValues (widget, value, size, 0, 0, False);
+ }
+ #else /* !USE_MOTIF i.e. use Xaw */
+
+ if (whole == 0)
+ top = 0, shown = 1;
+ else
+ {
+ top = (float) position / whole;
+ shown = (float) portion / whole;
+ }
+
+ {
+ float old_top, old_shown;
+ Dimension height;
+ XtVaGetValues (widget,
+ XtNtopOfThumb, &old_top,
+ XtNshown, &old_shown,
+ XtNheight, &height,
+ NULL);
+
+ /* Massage the top+shown values. */
+ if (NILP (bar->dragging) || last_scroll_bar_part == scroll_bar_down_arrow)
+ top = max (0, min (1, top));
+ else
+ top = old_top;
+ /* Keep two pixels available for moving the thumb down. */
+ shown = max (0, min (1 - top - (2.0 / height), shown));
+
+ /* If the call to XawScrollbarSetThumb below doesn't seem to work,
+ check that your system's configuration file contains a define
+ for `NARROWPROTO'. See s/freebsd.h for an example. */
+ if (top != old_top || shown != old_shown)
+ {
+ if (NILP (bar->dragging))
+ XawScrollbarSetThumb (widget, top, shown);
+ else
+ {
+ #ifdef HAVE_XAW3D
+ ScrollbarWidget sb = (ScrollbarWidget) widget;
+ int scroll_mode = 0;
+
+ /* `scroll_mode' only exists with Xaw3d + ARROW_SCROLLBAR. */
+ if (xaw3d_arrow_scroll)
+ {
+ /* Xaw3d stupidly ignores resize requests while dragging
+ so we have to make it believe it's not in dragging mode. */
+ scroll_mode = sb->scrollbar.scroll_mode;
+ if (scroll_mode == 2)
+ sb->scrollbar.scroll_mode = 0;
+ }
+ #endif
+ /* Try to make the scrolling a tad smoother. */
+ if (!xaw3d_pick_top)
+ shown = min (shown, old_shown);
+
+ XawScrollbarSetThumb (widget, top, shown);
+
+ #ifdef HAVE_XAW3D
+ if (xaw3d_arrow_scroll && scroll_mode == 2)
+ sb->scrollbar.scroll_mode = scroll_mode;
+ #endif
+ }
+ }
+ }
+ #endif /* !USE_MOTIF */
+
+ UNBLOCK_INPUT;
+ }
+ #endif /* not USE_GTK */
+
+ #endif /* USE_TOOLKIT_SCROLL_BARS */
+
+
+
+ /************************************************************************
+ Scroll bars, general
+ ************************************************************************/
+
+ /* Create a scroll bar and return the scroll bar vector for it. W is
+ the Emacs window on which to create the scroll bar. TOP, LEFT,
+ WIDTH and HEIGHT are the pixel coordinates and dimensions of the
+ scroll bar. */
+
+ static struct scroll_bar *
+ x_scroll_bar_create (w, top, left, width, height)
+ struct window *w;
+ int top, left, width, height;
+ {
+ struct frame *f = XFRAME (w->frame);
+ struct scroll_bar *bar
+ = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
+
+ BLOCK_INPUT;
+
+ #ifdef USE_TOOLKIT_SCROLL_BARS
+ x_create_toolkit_scroll_bar (f, bar);
+ #else /* not USE_TOOLKIT_SCROLL_BARS */
+ {
+ XSetWindowAttributes a;
+ unsigned long mask;
+ Window window;
+
+ a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
+ if (a.background_pixel == -1)
+ a.background_pixel = f->output_data.x->background_pixel;
+
+ a.event_mask = (ButtonPressMask | ButtonReleaseMask
+ | ButtonMotionMask | PointerMotionHintMask
+ | ExposureMask);
+ a.cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
+
+ mask = (CWBackPixel | CWEventMask | CWCursor);
+
+ /* Clear the area of W that will serve as a scroll bar. This is
+ for the case that a window has been split horizontally. In
+ this case, no clear_frame is generated to reduce flickering. */
+ if (width > 0 && height > 0)
+ x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ left, top, width,
+ window_box_height (w), False);
+
+ window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ /* Position and size of scroll bar. */
+ left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
+ top,
+ width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
+ height,
+ /* Border width, depth, class, and visual. */
+ 0,
+ CopyFromParent,
+ CopyFromParent,
+ CopyFromParent,
+ /* Attributes. */
+ mask, &a);
+ SET_SCROLL_BAR_X_WINDOW (bar, window);
+ }
+ #endif /* not USE_TOOLKIT_SCROLL_BARS */
+
+ XSETWINDOW (bar->window, w);
+ XSETINT (bar->top, top);
+ XSETINT (bar->left, left);
+ XSETINT (bar->width, width);
+ XSETINT (bar->height, height);
+ XSETINT (bar->start, 0);
+ XSETINT (bar->end, 0);
+ bar->dragging = Qnil;
+
+ /* Add bar to its frame's list of scroll bars. */
+ bar->next = FRAME_SCROLL_BARS (f);
+ bar->prev = Qnil;
+ XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
+ if (!NILP (bar->next))
+ XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
+
+ /* Map the window/widget. */
+ #ifdef USE_TOOLKIT_SCROLL_BARS
+ {
+ #ifdef USE_GTK
+ xg_update_scrollbar_pos (f,
+ SCROLL_BAR_X_WINDOW (bar),
+ top,
+ left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
+ width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
+ max (height, 1),
+ left,
+ width);
+ xg_show_scroll_bar (SCROLL_BAR_X_WINDOW (bar));
+ #else /* not USE_GTK */
+ Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
+ XtConfigureWidget (scroll_bar,
+ left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
+ top,
+ width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
+ max (height, 1), 0);
+ XtMapWidget (scroll_bar);
+ #endif /* not USE_GTK */
+ }
+ #else /* not USE_TOOLKIT_SCROLL_BARS */
+ XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
+ #endif /* not USE_TOOLKIT_SCROLL_BARS */
+
+ UNBLOCK_INPUT;
+ return bar;
+ }
+
+
+ /* Draw BAR's handle in the proper position.
+
+ If the handle is already drawn from START to END, don't bother
+ redrawing it, unless REBUILD is non-zero; in that case, always
+ redraw it. (REBUILD is handy for drawing the handle after expose
+ events.)
+
+ Normally, we want to constrain the start and end of the handle to
+ fit inside its rectangle, but if the user is dragging the scroll
+ bar handle, we want to let them drag it down all the way, so that
+ the bar's top is as far down as it goes; otherwise, there's no way
+ to move to the very end of the buffer. */
+
+ #ifndef USE_TOOLKIT_SCROLL_BARS
+
+ static void
+ x_scroll_bar_set_handle (bar, start, end, rebuild)
+ struct scroll_bar *bar;
+ int start, end;
+ int rebuild;
+ {
+ int dragging = ! NILP (bar->dragging);
+ Window w = SCROLL_BAR_X_WINDOW (bar);
+ FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+ GC gc = f->output_data.x->normal_gc;
+
+ /* If the display is already accurate, do nothing. */
+ if (! rebuild
+ && start == XINT (bar->start)
+ && end == XINT (bar->end))
+ return;
+
+ BLOCK_INPUT;
+
+ {
+ int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (f, XINT
(bar->width));
+ int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT
(bar->height));
+ int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
+
+ /* Make sure the values are reasonable, and try to preserve
+ the distance between start and end. */
+ {
+ int length = end - start;
+
+ if (start < 0)
+ start = 0;
+ else if (start > top_range)
+ start = top_range;
+ end = start + length;
+
+ if (end < start)
+ end = start;
+ else if (end > top_range && ! dragging)
+ end = top_range;
+ }
+
+ /* Store the adjusted setting in the scroll bar. */
+ XSETINT (bar->start, start);
+ XSETINT (bar->end, end);
+
+ /* Clip the end position, just for display. */
+ if (end > top_range)
+ end = top_range;
+
+ /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
+ below top positions, to make sure the handle is always at least
+ that many pixels tall. */
+ end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
+
+ /* Draw the empty space above the handle. Note that we can't clear
+ zero-height areas; that means "clear to end of window." */
+ if (0 < start)
+ x_clear_area (FRAME_X_DISPLAY (f), w,
+ /* x, y, width, height, and exposures. */
+ VERTICAL_SCROLL_BAR_LEFT_BORDER,
+ VERTICAL_SCROLL_BAR_TOP_BORDER,
+ inside_width, start,
+ False);
+
+ /* Change to proper foreground color if one is specified. */
+ if (f->output_data.x->scroll_bar_foreground_pixel != -1)
+ XSetForeground (FRAME_X_DISPLAY (f), gc,
+ f->output_data.x->scroll_bar_foreground_pixel);
+
+ /* Draw the handle itself. */
+ XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
+ /* x, y, width, height */
+ VERTICAL_SCROLL_BAR_LEFT_BORDER,
+ VERTICAL_SCROLL_BAR_TOP_BORDER + start,
+ inside_width, end - start);
+
+ /* Restore the foreground color of the GC if we changed it above. */
+ if (f->output_data.x->scroll_bar_foreground_pixel != -1)
+ XSetForeground (FRAME_X_DISPLAY (f), gc,
+ f->output_data.x->foreground_pixel);
+
+ /* Draw the empty space below the handle. Note that we can't
+ clear zero-height areas; that means "clear to end of window." */
+ if (end < inside_height)
+ x_clear_area (FRAME_X_DISPLAY (f), w,
+ /* x, y, width, height, and exposures. */
+ VERTICAL_SCROLL_BAR_LEFT_BORDER,
+ VERTICAL_SCROLL_BAR_TOP_BORDER + end,
+ inside_width, inside_height - end,
+ False);
+
+ }
+
+ UNBLOCK_INPUT;
+ }
+
+ #endif /* !USE_TOOLKIT_SCROLL_BARS */
+
+ /* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
+ nil. */
+
+ static void
+ x_scroll_bar_remove (bar)
+ struct scroll_bar *bar;
+ {
+ struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+ BLOCK_INPUT;
+
+ #ifdef USE_TOOLKIT_SCROLL_BARS
+ #ifdef USE_GTK
+ xg_remove_scroll_bar (f, SCROLL_BAR_X_WINDOW (bar));
+ #else /* not USE_GTK */
+ XtDestroyWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar));
+ #endif /* not USE_GTK */
+ #else
+ XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
+ #endif
+
+ /* Disassociate this scroll bar from its window. */
+ XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
+
+ UNBLOCK_INPUT;
+ }
+
+
+ /* Set the handle of the vertical scroll bar for WINDOW to indicate
+ that we are displaying PORTION characters out of a total of WHOLE
+ characters, starting at POSITION. If WINDOW has no scroll bar,
+ create one. */
+
+ static void
+ XTset_vertical_scroll_bar (w, portion, whole, position)
+ struct window *w;
+ int portion, whole, position;
+ {
+ struct frame *f = XFRAME (w->frame);
+ struct scroll_bar *bar;
+ int top, height, left, sb_left, width, sb_width;
+ int window_y, window_height;
+
+ /* Get window dimensions. */
+ window_box (w, -1, 0, &window_y, 0, &window_height);
+ top = window_y;
+ width = WINDOW_CONFIG_SCROLL_BAR_COLS (w) * FRAME_COLUMN_WIDTH (f);
+ height = window_height;
+
+ /* Compute the left edge of the scroll bar area. */
+ left = WINDOW_SCROLL_BAR_AREA_X (w);
+
+ /* Compute the width of the scroll bar which might be less than
+ the width of the area reserved for the scroll bar. */
+ if (WINDOW_CONFIG_SCROLL_BAR_WIDTH (w) > 0)
+ sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
+ else
+ sb_width = width;
+
+ /* Compute the left edge of the scroll bar. */
+ #ifdef USE_TOOLKIT_SCROLL_BARS
+ if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
+ sb_left = left + width - sb_width - (width - sb_width) / 2;
+ else
+ sb_left = left + (width - sb_width) / 2;
+ #else
+ if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
+ sb_left = left + width - sb_width;
+ else
+ sb_left = left;
+ #endif
+
+ /* Does the scroll bar exist yet? */
+ if (NILP (w->vertical_scroll_bar))
+ {
+ if (width > 0 && height > 0)
+ {
+ BLOCK_INPUT;
+ x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ left, top, width, height, False);
+ UNBLOCK_INPUT;
+ }
+
+ bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
+ }
+ else
+ {
+ /* It may just need to be moved and resized. */
+ unsigned int mask = 0;
+
+ bar = XSCROLL_BAR (w->vertical_scroll_bar);
+
+ BLOCK_INPUT;
+
+ if (sb_left != XINT (bar->left))
+ mask |= CWX;
+ if (top != XINT (bar->top))
+ mask |= CWY;
+ if (sb_width != XINT (bar->width))
+ mask |= CWWidth;
+ if (height != XINT (bar->height))
+ mask |= CWHeight;
+
+ #ifdef USE_TOOLKIT_SCROLL_BARS
+
+ #ifdef USE_GTK
+ if (mask)
+ xg_update_scrollbar_pos (f,
+ SCROLL_BAR_X_WINDOW (bar),
+ top,
+ sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
+ sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM *
2,
+ max (height, 1),
+ left,
+ width);
+ #else /* not USE_GTK */
+
+ /* Since toolkit scroll bars are smaller than the space reserved
+ for them on the frame, we have to clear "under" them. */
+ if (width > 0 && height > 0)
+ x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ left, top, width, height, False);
+ /* Move/size the scroll bar widget. */
+ if (mask)
+ XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar),
+ sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
+ top,
+ sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
+ max (height, 1), 0);
+
+ #endif /* not USE_GTK */
+ #else /* not USE_TOOLKIT_SCROLL_BARS */
+
+ /* Clear areas not covered by the scroll bar because of
+ VERTICAL_SCROLL_BAR_WIDTH_TRIM. */
+ if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
+ {
+ x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
+ height, False);
+ x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
+ top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
+ height, False);
+ }
+
+ /* Clear areas not covered by the scroll bar because it's not as
+ wide as the area reserved for it. This makes sure a
+ previous mode line display is cleared after C-x 2 C-x 1, for
+ example. */
+ {
+ int area_width = WINDOW_CONFIG_SCROLL_BAR_COLS (w) * FRAME_COLUMN_WIDTH
(f);
+ int rest = area_width - sb_width;
+ if (rest > 0 && height > 0)
+ {
+ if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
+ x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ left + area_width - rest, top,
+ rest, height, False);
+ else
+ x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ left, top, rest, height, False);
+ }
+ }
+
+ /* Move/size the scroll bar window. */
+ if (mask)
+ {
+ XWindowChanges wc;
+
+ wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
+ wc.y = top;
+ wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
+ wc.height = height;
+ XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
+ mask, &wc);
+ }
+
+ #endif /* not USE_TOOLKIT_SCROLL_BARS */
+
+ /* Remember new settings. */
+ XSETINT (bar->left, sb_left);
+ XSETINT (bar->top, top);
+ XSETINT (bar->width, sb_width);
+ XSETINT (bar->height, height);
+
+ UNBLOCK_INPUT;
+ }
+
+ #ifdef USE_TOOLKIT_SCROLL_BARS
+ x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
+ #else /* not USE_TOOLKIT_SCROLL_BARS */
+ /* Set the scroll bar's current state, unless we're currently being
+ dragged. */
+ if (NILP (bar->dragging))
+ {
+ int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
+
+ if (whole == 0)
+ x_scroll_bar_set_handle (bar, 0, top_range, 0);
+ else
+ {
+ int start = ((double) position * top_range) / whole;
+ int end = ((double) (position + portion) * top_range) / whole;
+ x_scroll_bar_set_handle (bar, start, end, 0);
+ }
+ }
+ #endif /* not USE_TOOLKIT_SCROLL_BARS */
+
+ XSETVECTOR (w->vertical_scroll_bar, bar);
+ }
+
+
+ /* The following three hooks are used when we're doing a thorough
+ redisplay of the frame. We don't explicitly know which scroll bars
+ are going to be deleted, because keeping track of when windows go
+ away is a real pain - "Can you say set-window-configuration, boys
+ and girls?" Instead, we just assert at the beginning of redisplay
+ that *all* scroll bars are to be removed, and then save a scroll bar
+ from the fiery pit when we actually redisplay its window. */
+
+ /* Arrange for all scroll bars on FRAME to be removed at the next call
+ to `*judge_scroll_bars_hook'. A scroll bar may be spared if
+ `*redeem_scroll_bar_hook' is applied to its window before the judgment. */
+
+ static void
+ XTcondemn_scroll_bars (frame)
+ FRAME_PTR frame;
+ {
+ /* Transfer all the scroll bars to FRAME_CONDEMNED_SCROLL_BARS. */
+ while (! NILP (FRAME_SCROLL_BARS (frame)))
+ {
+ Lisp_Object bar;
+ bar = FRAME_SCROLL_BARS (frame);
+ FRAME_SCROLL_BARS (frame) = XSCROLL_BAR (bar)->next;
+ XSCROLL_BAR (bar)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
+ XSCROLL_BAR (bar)->prev = Qnil;
+ if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
+ XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = bar;
+ FRAME_CONDEMNED_SCROLL_BARS (frame) = bar;
+ }
+ }
+
+
+ /* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
+ Note that WINDOW isn't necessarily condemned at all. */
+
+ static void
+ XTredeem_scroll_bar (window)
+ struct window *window;
+ {
+ struct scroll_bar *bar;
+ struct frame *f;
+
+ /* We can't redeem this window's scroll bar if it doesn't have one. */
+ if (NILP (window->vertical_scroll_bar))
+ abort ();
+
+ bar = XSCROLL_BAR (window->vertical_scroll_bar);
+
+ /* Unlink it from the condemned list. */
+ f = XFRAME (WINDOW_FRAME (window));
+ if (NILP (bar->prev))
+ {
+ /* If the prev pointer is nil, it must be the first in one of
+ the lists. */
+ if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
+ /* It's not condemned. Everything's fine. */
+ return;
+ else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
+ window->vertical_scroll_bar))
+ FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
+ else
+ /* If its prev pointer is nil, it must be at the front of
+ one or the other! */
+ abort ();
+ }
+ else
+ XSCROLL_BAR (bar->prev)->next = bar->next;
+
+ if (! NILP (bar->next))
+ XSCROLL_BAR (bar->next)->prev = bar->prev;
+
+ bar->next = FRAME_SCROLL_BARS (f);
+ bar->prev = Qnil;
+ XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
+ if (! NILP (bar->next))
+ XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
+ }
+
+ /* Remove all scroll bars on FRAME that haven't been saved since the
+ last call to `*condemn_scroll_bars_hook'. */
+
+ static void
+ XTjudge_scroll_bars (f)
+ FRAME_PTR f;
+ {
+ Lisp_Object bar, next;
+
+ bar = FRAME_CONDEMNED_SCROLL_BARS (f);
+
+ /* Clear out the condemned list now so we won't try to process any
+ more events on the hapless scroll bars. */
+ FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
+
+ for (; ! NILP (bar); bar = next)
+ {
+ struct scroll_bar *b = XSCROLL_BAR (bar);
+
+ x_scroll_bar_remove (b);
+
+ next = b->next;
+ b->next = b->prev = Qnil;
+ }
+
+ /* Now there should be no references to the condemned scroll bars,
+ and they should get garbage-collected. */
+ }
+
+
+ #ifndef USE_TOOLKIT_SCROLL_BARS
+ /* Handle an Expose or GraphicsExpose event on a scroll bar. This
+ is a no-op when using toolkit scroll bars.
+
+ This may be called from a signal handler, so we have to ignore GC
+ mark bits. */
+
+ static void
+ x_scroll_bar_expose (bar, event)
+ struct scroll_bar *bar;
+ XEvent *event;
+ {
+ Window w = SCROLL_BAR_X_WINDOW (bar);
+ FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+ GC gc = f->output_data.x->normal_gc;
+ int width_trim = VERTICAL_SCROLL_BAR_WIDTH_TRIM;
+
+ BLOCK_INPUT;
+
+ x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
+
+ /* Draw a one-pixel border just inside the edges of the scroll bar. */
+ XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
+
+ /* x, y, width, height */
+ 0, 0,
+ XINT (bar->width) - 1 - width_trim - width_trim,
+ XINT (bar->height) - 1);
+
+ UNBLOCK_INPUT;
+
+ }
+ #endif /* not USE_TOOLKIT_SCROLL_BARS */
+
+ /* Handle a mouse click on the scroll bar BAR. If *EMACS_EVENT's kind
+ is set to something other than NO_EVENT, it is enqueued.
+
+ This may be called from a signal handler, so we have to ignore GC
+ mark bits. */
+
+
+ static void
+ x_scroll_bar_handle_click (bar, event, emacs_event)
+ struct scroll_bar *bar;
+ XEvent *event;
+ struct input_event *emacs_event;
+ {
+ if (! GC_WINDOWP (bar->window))
+ abort ();
+
+ emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
+ emacs_event->code = event->xbutton.button - Button1;
+ emacs_event->modifiers
+ = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO
+ (XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))),
+ event->xbutton.state)
+ | (event->type == ButtonRelease
+ ? up_modifier
+ : down_modifier));
+ emacs_event->frame_or_window = bar->window;
+ emacs_event->arg = Qnil;
+ emacs_event->timestamp = event->xbutton.time;
+ {
+ #if 0
+ FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+ int internal_height
+ = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
+ #endif
+ int top_range
+ = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
+ int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
+
+ if (y < 0) y = 0;
+ if (y > top_range) y = top_range;
+
+ if (y < XINT (bar->start))
+ emacs_event->part = scroll_bar_above_handle;
+ else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
+ emacs_event->part = scroll_bar_handle;
+ else
+ emacs_event->part = scroll_bar_below_handle;
+
+ /* Just because the user has clicked on the handle doesn't mean
+ they want to drag it. Lisp code needs to be able to decide
+ whether or not we're dragging. */
+ #if 0
+ /* If the user has just clicked on the handle, record where they're
+ holding it. */
+ if (event->type == ButtonPress
+ && emacs_event->part == scroll_bar_handle)
+ XSETINT (bar->dragging, y - XINT (bar->start));
+ #endif
+
+ #ifndef USE_TOOLKIT_SCROLL_BARS
+ /* If the user has released the handle, set it to its final position. */
+ if (event->type == ButtonRelease
+ && ! NILP (bar->dragging))
+ {
+ int new_start = y - XINT (bar->dragging);
+ int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
+
+ x_scroll_bar_set_handle (bar, new_start, new_end, 0);
+ bar->dragging = Qnil;
+ }
+ #endif
+
+ /* Same deal here as the other #if 0. */
+ #if 0
+ /* Clicks on the handle are always reported as occurring at the top of
+ the handle. */
+ if (emacs_event->part == scroll_bar_handle)
+ emacs_event->x = bar->start;
+ else
+ XSETINT (emacs_event->x, y);
+ #else
+ XSETINT (emacs_event->x, y);
+ #endif
+
+ XSETINT (emacs_event->y, top_range);
+ }
+ }
+
+ #ifndef USE_TOOLKIT_SCROLL_BARS
+
+ /* Handle some mouse motion while someone is dragging the scroll bar.
+
+ This may be called from a signal handler, so we have to ignore GC
+ mark bits. */
+
+ static void
+ x_scroll_bar_note_movement (bar, event)
+ struct scroll_bar *bar;
+ XEvent *event;
+ {
+ FRAME_PTR f = XFRAME (XWINDOW (bar->window)->frame);
+
+ last_mouse_movement_time = event->xmotion.time;
+
+ f->mouse_moved = 1;
+ XSETVECTOR (last_mouse_scroll_bar, bar);
+
+ /* If we're dragging the bar, display it. */
+ if (! GC_NILP (bar->dragging))
+ {
+ /* Where should the handle be now? */
+ int new_start = event->xmotion.y - XINT (bar->dragging);
+
+ if (new_start != XINT (bar->start))
+ {
+ int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
+
+ x_scroll_bar_set_handle (bar, new_start, new_end, 0);
+ }
+ }
+ }
+
+ #endif /* !USE_TOOLKIT_SCROLL_BARS */
+
+ /* Return information to the user about the current position of the mouse
+ on the scroll bar. */
+
+ static void
+ x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
+ FRAME_PTR *fp;
+ Lisp_Object *bar_window;
+ enum scroll_bar_part *part;
+ Lisp_Object *x, *y;
+ unsigned long *time;
+ {
+ struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
+ Window w = SCROLL_BAR_X_WINDOW (bar);
+ FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+ int win_x, win_y;
+ Window dummy_window;
+ int dummy_coord;
+ unsigned int dummy_mask;
+
+ BLOCK_INPUT;
+
+ /* Get the mouse's position relative to the scroll bar window, and
+ report that. */
+ if (! XQueryPointer (FRAME_X_DISPLAY (f), w,
+
+ /* Root, child, root x and root y. */
+ &dummy_window, &dummy_window,
+ &dummy_coord, &dummy_coord,
+
+ /* Position relative to scroll bar. */
+ &win_x, &win_y,
+
+ /* Mouse buttons and modifier keys. */
+ &dummy_mask))
+ ;
+ else
+ {
+ #if 0
+ int inside_height
+ = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
+ #endif
+ int top_range
+ = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
+
+ win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
+
+ if (! NILP (bar->dragging))
+ win_y -= XINT (bar->dragging);
+
+ if (win_y < 0)
+ win_y = 0;
+ if (win_y > top_range)
+ win_y = top_range;
+
+ *fp = f;
+ *bar_window = bar->window;
+
+ if (! NILP (bar->dragging))
+ *part = scroll_bar_handle;
+ else if (win_y < XINT (bar->start))
+ *part = scroll_bar_above_handle;
+ else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
+ *part = scroll_bar_handle;
+ else
+ *part = scroll_bar_below_handle;
+
+ XSETINT (*x, win_y);
+ XSETINT (*y, top_range);
+
+ f->mouse_moved = 0;
+ last_mouse_scroll_bar = Qnil;
+ }
+
+ *time = last_mouse_movement_time;
+
+ UNBLOCK_INPUT;
+ }
+
+
+ /* The screen has been cleared so we may have changed foreground or
+ background colors, and the scroll bars may need to be redrawn.
+ Clear out the scroll bars, and ask for expose events, so we can
+ redraw them. */
+
+ void
+ x_scroll_bar_clear (f)
+ FRAME_PTR f;
+ {
+ #ifndef USE_TOOLKIT_SCROLL_BARS
+ Lisp_Object bar;
+
+ /* We can have scroll bars even if this is 0,
+ if we just turned off scroll bar mode.
+ But in that case we should not clear them. */
+ if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+ for (bar = FRAME_SCROLL_BARS (f); VECTORP (bar);
+ bar = XSCROLL_BAR (bar)->next)
+ XClearArea (FRAME_X_DISPLAY (f),
+ SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
+ 0, 0, 0, 0, True);
+ #endif /* not USE_TOOLKIT_SCROLL_BARS */
+ }
+
+
+ /* Define a queue to save up SelectionRequest events for later handling. */
+
+ struct selection_event_queue
+ {
+ XEvent event;
+ struct selection_event_queue *next;
+ };
+
+ static struct selection_event_queue *queue;
+
+ /* Nonzero means queue up certain events--don't process them yet. */
+
+ static int x_queue_selection_requests;
+
+ /* Queue up an X event *EVENT, to be processed later. */
+
+ static void
+ x_queue_event (f, event)
+ FRAME_PTR f;
+ XEvent *event;
+ {
+ struct selection_event_queue *queue_tmp
+ = (struct selection_event_queue *) xmalloc (sizeof (struct
selection_event_queue));
+
+ if (queue_tmp != NULL)
+ {
+ queue_tmp->event = *event;
+ queue_tmp->next = queue;
+ queue = queue_tmp;
+ }
+ }
+
+ /* Take all the queued events and put them back
+ so that they get processed afresh. */
+
+ static void
+ x_unqueue_events (display)
+ Display *display;
+ {
+ while (queue != NULL)
+ {
+ struct selection_event_queue *queue_tmp = queue;
+ XPutBackEvent (display, &queue_tmp->event);
+ queue = queue_tmp->next;
+ xfree ((char *)queue_tmp);
+ }
+ }
+
+ /* Start queuing SelectionRequest events. */
+
+ void
+ x_start_queuing_selection_requests (display)
+ Display *display;
+ {
+ x_queue_selection_requests++;
+ }
+
+ /* Stop queuing SelectionRequest events. */
+
+ void
+ x_stop_queuing_selection_requests (display)
+ Display *display;
+ {
+ x_queue_selection_requests--;
+ x_unqueue_events (display);
+ }
+
+ /* The main X event-reading loop - XTread_socket. */
+
+ #if 0
+ /* Time stamp 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;
+ #endif
+
+ /* This holds the state XLookupString needs to implement dead keys
+ and other tricks known as "compose processing". _X Window System_
+ says that a portable program can't use this, but Stephen Gildea assures
+ me that letting the compiler initialize it to zeros will work okay.
+
+ This must be defined outside of XTread_socket, for the same reasons
+ given for enter_timestamp, above. */
+
+ static XComposeStatus compose_status;
+
+ /* Record the last 100 characters stored
+ to help debug the loss-of-chars-during-GC problem. */
+
+ static int temp_index;
+ static short temp_buffer[100];
+
+ /* Set this to nonzero to fake an "X I/O error"
+ on a particular display. */
+
+ struct x_display_info *XTread_socket_fake_io_error;
+
+ /* When we find no input here, we occasionally do a no-op command
+ to verify that the X server is still running and we can still talk with it.
+ We try all the open displays, one by one.
+ This variable is used for cycling thru the displays. */
+
+ static struct x_display_info *next_noop_dpyinfo;
+
+ #define SET_SAVED_MENU_EVENT(size) \
+ do
\
+ { \
+ if (f->output_data.x->saved_menu_event == 0) \
+ f->output_data.x->saved_menu_event \
+ = (XEvent *) xmalloc (sizeof (XEvent)); \
+ bcopy (&event, f->output_data.x->saved_menu_event, size); \
+ if (numchars >= 1) \
+ { \
+ bufp->kind = MENU_BAR_ACTIVATE_EVENT; \
+ XSETFRAME (bufp->frame_or_window, f); \
+ bufp->arg = Qnil;
\
+ bufp++; \
+ count++; \
+ numchars--; \
+ } \
+ } \
+ while (0)
+
+ #define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
+ #define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
+
+
+ enum
+ {
+ X_EVENT_NORMAL,
+ X_EVENT_GOTO_OUT,
+ X_EVENT_DROP
+ };
+
+ /* Filter events for the current X input method.
+ DPYINFO is the display this event is for.
+ EVENT is the X event to filter.
+
+ Returns non-zero if the event was filtered, caller shall not process
+ this event further.
+ Returns zero if event is wasn't filtered. */
+
+ #ifdef HAVE_X_I18N
+ static int
+ x_filter_event (dpyinfo, event)
+ struct x_display_info *dpyinfo;
+ XEvent *event;
+ {
+ /* XFilterEvent returns non-zero if the input method has
+ consumed the event. We pass the frame's X window to
+ XFilterEvent because that's the one for which the IC
+ was created. */
+
+ struct frame *f1 = x_any_window_to_frame (dpyinfo,
+ event->xclient.window);
+
+ return XFilterEvent (event, f1 ? FRAME_X_WINDOW (f1) : None);
+ }
+ #endif
+
+ #ifdef USE_GTK
+ static struct x_display_info *current_dpyinfo;
+ static struct input_event **current_bufp;
+ static int *current_numcharsp;
+ static int current_count;
+ static int current_finish;
+
+ /* This is the filter function invoked by the GTK event loop.
+ It is invoked before the XEvent is translated to a GdkEvent,
+ so we have a chanse to act on the event before GTK. */
+ static GdkFilterReturn
+ event_handler_gdk (gxev, ev, data)
+ GdkXEvent *gxev;
+ GdkEvent *ev;
+ gpointer data;
+ {
+ XEvent *xev = (XEvent*)gxev;
+
+ if (current_numcharsp)
+ {
+ #ifdef HAVE_X_I18N
+ /* Filter events for the current X input method.
+ GTK calls XFilterEvent but not for key press and release,
+ so we do it here. */
+ if (xev->type == KeyPress || xev->type == KeyRelease)
+ if (x_filter_event (current_dpyinfo, xev))
+ return GDK_FILTER_REMOVE;
+ #endif
+ current_count += handle_one_xevent (current_dpyinfo,
+ xev,
+ current_bufp,
+ current_numcharsp,
+ ¤t_finish);
+ }
+ else
+ current_finish = x_dispatch_event (xev, GDK_DISPLAY ());
+
+ if (current_finish == X_EVENT_GOTO_OUT || current_finish == X_EVENT_DROP)
+ return GDK_FILTER_REMOVE;
+
+ return GDK_FILTER_CONTINUE;
+ }
+ #endif /* USE_GTK */
+
+
+ /* Handles the XEvent EVENT on display DPYINFO.
+
+ *FINISH is X_EVENT_GOTO_OUT if caller should stop reading events.
+ *FINISH is zero if caller should continue reading events.
+ *FINISH is X_EVENT_DROP if event should not be passed to the toolkit.
+
+ Events representing keys are stored in buffer *BUFP_R,
+ which can hold up to *NUMCHARSP characters.
+ We return the number of characters stored into the buffer. */
+
+ static int
+ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish)
+ struct x_display_info *dpyinfo;
+ XEvent *eventp;
+ /* register */ struct input_event **bufp_r;
+ /* register */ int *numcharsp;
+ int *finish;
+ {
+ int count = 0;
+ int nbytes = 0;
+ struct frame *f;
+ struct coding_system coding;
+ struct input_event *bufp = *bufp_r;
+ int numchars = *numcharsp;
+ XEvent event = *eventp;
+
+ *finish = X_EVENT_NORMAL;
+
+ switch (event.type)
+ {
+ case ClientMessage:
+ {
+ if (event.xclient.message_type
+ == dpyinfo->Xatom_wm_protocols
+ && event.xclient.format == 32)
+ {
+ if (event.xclient.data.l[0]
+ == dpyinfo->Xatom_wm_take_focus)
+ {
+ /* Use x_any_window_to_frame because this
+ could be the shell widget window
+ if the frame has no title bar. */
+ f = x_any_window_to_frame (dpyinfo, event.xclient.window);
+ #ifdef HAVE_X_I18N
+ /* Not quite sure this is needed -pd */
+ if (f && FRAME_XIC (f))
+ XSetICFocus (FRAME_XIC (f));
+ #endif
+ #if 0 /* Emacs sets WM hints whose `input' field is `true'. This
+ instructs the WM to set the input focus automatically for
+ Emacs with a call to XSetInputFocus. Setting WM_TAKE_FOCUS
+ tells the WM to send us a ClientMessage WM_TAKE_FOCUS after
+ it has set the focus. So, XSetInputFocus below is not
+ needed.
+
+ The call to XSetInputFocus below has also caused trouble. In
+ cases where the XSetInputFocus done by the WM and the one
+ below are temporally close (on a fast machine), the call
+ below can generate additional FocusIn events which confuse
+ Emacs. */
+
+ /* Since we set WM_TAKE_FOCUS, we must call
+ XSetInputFocus explicitly. But not if f is null,
+ since that might be an event for a deleted frame. */
+ if (f)
+ {
+ Display *d = event.xclient.display;
+ /* Catch and ignore errors, in case window has been
+ iconified by a window manager such as GWM. */
+ int count = x_catch_errors (d);
+ XSetInputFocus (d, event.xclient.window,
+ /* The ICCCM says this is
+ the only valid choice. */
+ RevertToParent,
+ event.xclient.data.l[1]);
+ /* This is needed to detect the error
+ if there is an error. */
+ XSync (d, False);
+ x_uncatch_errors (d, count);
+ }
+ /* Not certain about handling scroll bars here */
+ #endif /* 0 */
+ }
+ else if (event.xclient.data.l[0]
+ == dpyinfo->Xatom_wm_save_yourself)
+ {
+ /* Save state modify the WM_COMMAND property to
+ something which can reinstate us. This notifies
+ the session manager, who's looking for such a
+ PropertyNotify. Can restart processing when
+ a keyboard or mouse event arrives. */
+ /* If we have a session manager, don't set this.
+ KDE will then start two Emacsen, one for the
+ session manager and one for this. */
+ if (numchars > 0
+ #ifdef HAVE_X_SM
+ && ! x_session_have_connection ()
+ #endif
+ )
+ {
+ f = x_top_window_to_frame (dpyinfo,
+ event.xclient.window);
+ /* This is just so we only give real data once
+ for a single Emacs process. */
+ if (f == SELECTED_FRAME ())
+ XSetCommand (FRAME_X_DISPLAY (f),
+ event.xclient.window,
+ initial_argv, initial_argc);
+ else if (f)
+ XSetCommand (FRAME_X_DISPLAY (f),
+ event.xclient.window,
+ 0, 0);
+ }
+ }
+ else if (event.xclient.data.l[0]
+ == dpyinfo->Xatom_wm_delete_window)
+ {
+ struct frame *f
+ = x_any_window_to_frame (dpyinfo,
+ event.xclient.window);
+
+ if (f)
+ {
+ if (numchars == 0)
+ abort ();
+
+ bufp->kind = DELETE_WINDOW_EVENT;
+ XSETFRAME (bufp->frame_or_window, f);
+ bufp->arg = Qnil;
+ bufp++;
+
+ count += 1;
+ numchars -= 1;
+ }
+ else
+ goto OTHER; /* May be a dialog that is to be removed */
+ }
+ }
+ else if (event.xclient.message_type
+ == dpyinfo->Xatom_wm_configure_denied)
+ {
+ }
+ else if (event.xclient.message_type
+ == dpyinfo->Xatom_wm_window_moved)
+ {
+ int new_x, new_y;
+ struct frame *f
+ = x_window_to_frame (dpyinfo, event.xclient.window);
+
+ new_x = event.xclient.data.s[0];
+ new_y = event.xclient.data.s[1];
+
+ if (f)
+ {
+ f->left_pos = new_x;
+ f->top_pos = new_y;
+ }
+ }
+ #ifdef HACK_EDITRES
+ else if (event.xclient.message_type
+ == dpyinfo->Xatom_editres)
+ {
+ struct frame *f
+ = x_any_window_to_frame (dpyinfo, event.xclient.window);
+ _XEditResCheckMessages (f->output_data.x->widget, NULL,
+ &event, NULL);
+ }
+ #endif /* HACK_EDITRES */
+ else if ((event.xclient.message_type
+ == dpyinfo->Xatom_DONE)
+ || (event.xclient.message_type
+ == dpyinfo->Xatom_PAGE))
+ {
+ /* Ghostview job completed. Kill it. We could
+ reply with "Next" if we received "Page", but we
+ currently never do because we are interested in
+ images, only, which should have 1 page. */
+ Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
+ struct frame *f
+ = x_window_to_frame (dpyinfo, event.xclient.window);
+ x_kill_gs_process (pixmap, f);
+ expose_frame (f, 0, 0, 0, 0);
+ }
+ #ifdef USE_TOOLKIT_SCROLL_BARS
+ /* Scroll bar callbacks send a ClientMessage from which
+ we construct an input_event. */
+ else if (event.xclient.message_type
+ == dpyinfo->Xatom_Scrollbar)
+ {
+ x_scroll_bar_to_input_event (&event, bufp);
+ ++bufp, ++count, --numchars;
+ goto out;
+ }
+ #endif /* USE_TOOLKIT_SCROLL_BARS */
+ else
+ goto OTHER;
+ }
+ break;
+
+ case SelectionNotify:
+ #ifdef USE_X_TOOLKIT
+ if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
+ goto OTHER;
+ #endif /* not USE_X_TOOLKIT */
+ x_handle_selection_notify (&event.xselection);
+ break;
+
+ case SelectionClear: /* Someone has grabbed ownership. */
+ #ifdef USE_X_TOOLKIT
+ if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
+ goto OTHER;
+ #endif /* USE_X_TOOLKIT */
+ {
+ XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
+
+ if (numchars == 0)
+ abort ();
+
+ bufp->kind = SELECTION_CLEAR_EVENT;
+ SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
+ SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
+ SELECTION_EVENT_TIME (bufp) = eventp->time;
+ bufp->frame_or_window = Qnil;
+ bufp->arg = Qnil;
+ bufp++;
+
+ count += 1;
+ numchars -= 1;
+ }
+ break;
+
+ case SelectionRequest: /* Someone wants our selection. */
+ #ifdef USE_X_TOOLKIT
+ if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
+ goto OTHER;
+ #endif /* USE_X_TOOLKIT */
+ if (x_queue_selection_requests)
+ x_queue_event (x_window_to_frame (dpyinfo,
event.xselectionrequest.owner),
+ &event);
+ else
+ {
+ XSelectionRequestEvent *eventp
+ = (XSelectionRequestEvent *) &event;
+
+ if (numchars == 0)
+ abort ();
+
+ bufp->kind = SELECTION_REQUEST_EVENT;
+ SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
+ SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
+ SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
+ SELECTION_EVENT_TARGET (bufp) = eventp->target;
+ SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
+ SELECTION_EVENT_TIME (bufp) = eventp->time;
+ bufp->frame_or_window = Qnil;
+ bufp->arg = Qnil;
+ bufp++;
+
+ count += 1;
+ numchars -= 1;
+ }
+ break;
+
+ case PropertyNotify:
+ #if 0 /* This is plain wrong. In the case that we are waiting for a
+ PropertyNotify used as an ACK in incremental selection
+ transfer, the property will be on the receiver's window. */
+ #if defined USE_X_TOOLKIT
+ if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
+ goto OTHER;
+ #endif
+ #endif
+ x_handle_property_notify (&event.xproperty);
+ goto OTHER;
+
+ case ReparentNotify:
+ f = x_top_window_to_frame (dpyinfo, event.xreparent.window);
+ if (f)
+ {
+ int x, y;
+ f->output_data.x->parent_desc = event.xreparent.parent;
+ x_real_positions (f, &x, &y);
+ f->left_pos = x;
+ f->top_pos = y;
+ }
+ goto OTHER;
+ break;
+
+ case Expose:
+ f = x_window_to_frame (dpyinfo, event.xexpose.window);
+ if (f)
+ {
+ x_check_fullscreen (f);
+
+ if (f->async_visible == 0)
+ {
+ f->async_visible = 1;
+ f->async_iconified = 0;
+ f->output_data.x->has_been_visible = 1;
+ SET_FRAME_GARBAGED (f);
+ }
+ else
+ expose_frame (f,
+ event.xexpose.x, event.xexpose.y,
+ event.xexpose.width, event.xexpose.height);
+ }
+ else
+ {
+ #ifndef USE_TOOLKIT_SCROLL_BARS
+ struct scroll_bar *bar;
+ #endif
+ #if defined USE_LUCID
+ /* Submenus of the Lucid menu bar aren't widgets
+ themselves, so there's no way to dispatch events
+ to them. Recognize this case separately. */
+ {
+ Widget widget
+ = x_window_to_menu_bar (event.xexpose.window);
+ if (widget)
+ xlwmenu_redisplay (widget);
+ }
+ #endif /* USE_LUCID */
+
+ #ifdef USE_TOOLKIT_SCROLL_BARS
+ /* Dispatch event to the widget. */
+ goto OTHER;
+ #else /* not USE_TOOLKIT_SCROLL_BARS */
+ bar = x_window_to_scroll_bar (event.xexpose.window);
+
+ if (bar)
+ x_scroll_bar_expose (bar, &event);
+ #ifdef USE_X_TOOLKIT
+ else
+ goto OTHER;
+ #endif /* USE_X_TOOLKIT */
+ #endif /* not USE_TOOLKIT_SCROLL_BARS */
+ }
+ break;
+
+ case GraphicsExpose: /* This occurs when an XCopyArea's
+ source area was obscured or not
+ available. */
+ f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
+ if (f)
+ {
+ expose_frame (f,
+ event.xgraphicsexpose.x, event.xgraphicsexpose.y,
+ event.xgraphicsexpose.width,
+ event.xgraphicsexpose.height);
+ }
+ #ifdef USE_X_TOOLKIT
+ else
+ goto OTHER;
+ #endif /* USE_X_TOOLKIT */
+ break;
+
+ case NoExpose: /* This occurs when an XCopyArea's
+ source area was completely
+ available. */
+ break;
+
+ case UnmapNotify:
+ /* Redo the mouse-highlight after the tooltip has gone. */
+ if (event.xmap.window == tip_window)
+ {
+ tip_window = 0;
+ redo_mouse_highlight ();
+ }
+
+ f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
+ if (f) /* F may no longer exist if
+ the frame was deleted. */
+ {
+ /* While a frame is unmapped, display generation is
+ disabled; you don't want to spend time updating a
+ display that won't ever be seen. */
+ f->async_visible = 0;
+ /* We can't distinguish, from the event, whether the window
+ has become iconified or invisible. So assume, if it
+ was previously visible, than now it is iconified.
+ But x_make_frame_invisible clears both
+ the visible flag and the iconified flag;
+ and that way, we know the window is not iconified now. */
+ if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
+ {
+ f->async_iconified = 1;
+
+ bufp->kind = ICONIFY_EVENT;
+ XSETFRAME (bufp->frame_or_window, f);
+ bufp->arg = Qnil;
+ bufp++;
+ count++;
+ numchars--;
+ }
+ }
+ goto OTHER;
+
+ case MapNotify:
+ if (event.xmap.window == tip_window)
+ /* The tooltip has been drawn already. Avoid
+ the SET_FRAME_GARBAGED below. */
+ goto OTHER;
+
+ /* We use x_top_window_to_frame because map events can
+ come for sub-windows and they don't mean that the
+ frame is visible. */
+ f = x_top_window_to_frame (dpyinfo, event.xmap.window);
+ if (f)
+ {
+ /* wait_reading_process_input will notice this and update
+ the frame's display structures.
+ If we where iconified, we should not set garbaged,
+ because that stops redrawing on Expose events. This looks
+ bad if we are called from a recursive event loop
+ (x_dispatch_event), for example when a dialog is up. */
+ if (! f->async_iconified)
+ SET_FRAME_GARBAGED (f);
+
+ f->async_visible = 1;
+ f->async_iconified = 0;
+ f->output_data.x->has_been_visible = 1;
+
+ if (f->iconified)
+ {
+ bufp->kind = DEICONIFY_EVENT;
+ XSETFRAME (bufp->frame_or_window, f);
+ bufp->arg = Qnil;
+ bufp++;
+ count++;
+ numchars--;
+ }
+ else if (! NILP (Vframe_list)
+ && ! NILP (XCDR (Vframe_list)))
+ /* Force a redisplay sooner or later
+ to update the frame titles
+ in case this is the second frame. */
+ record_asynch_buffer_change ();
+ }
+ goto OTHER;
+
+ case KeyPress:
+
+ #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
+ /* Dispatch KeyPress events when in menu. */
+ if (popup_activated ())
+ goto OTHER;
+ #endif
+
+ f = x_any_window_to_frame (dpyinfo, event.xkey.window);
+
+ if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
+ {
+ dpyinfo->mouse_face_hidden = 1;
+ clear_mouse_face (dpyinfo);
+ }
+
+ #if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
+ if (f == 0)
+ {
+ /* Scroll bars consume key events, but we want
+ the keys to go to the scroll bar's frame. */
+ Widget widget = XtWindowToWidget (dpyinfo->display,
+ event.xkey.window);
+ if (widget && XmIsScrollBar (widget))
+ {
+ widget = XtParent (widget);
+ f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
+ }
+ }
+ #endif /* USE_MOTIF and USE_TOOLKIT_SCROLL_BARS */
+
+ if (f != 0)
+ {
+ KeySym keysym, orig_keysym;
+ /* address@hidden says that making this 81
+ instead of 80 fixed a bug whereby meta chars made
+ his Emacs hang.
+
+ It seems that some version of XmbLookupString has
+ a bug of not returning XBufferOverflow in
+ status_return even if the input is too long to
+ fit in 81 bytes. So, we must prepare sufficient
+ bytes for copy_buffer. 513 bytes (256 chars for
+ two-byte character set) seems to be a fairly good
+ approximation. -- 2000.8.10 address@hidden */
+ unsigned char copy_buffer[513];
+ unsigned char *copy_bufptr = copy_buffer;
+ int copy_bufsiz = sizeof (copy_buffer);
+ int modifiers;
+ Lisp_Object coding_system = Qlatin_1;
+
+ event.xkey.state
+ |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
+ extra_keyboard_modifiers);
+ modifiers = event.xkey.state;
+
+ /* This will have to go some day... */
+
+ /* make_lispy_event turns chars into control chars.
+ Don't do it here because XLookupString is too eager. */
+ event.xkey.state &= ~ControlMask;
+ event.xkey.state &= ~(dpyinfo->meta_mod_mask
+ | dpyinfo->super_mod_mask
+ | dpyinfo->hyper_mod_mask
+ | dpyinfo->alt_mod_mask);
+
+ /* In case Meta is ComposeCharacter,
+ clear its status. According to Markus Ehrnsperger
+ address@hidden
+ this enables ComposeCharacter to work whether or
+ not it is combined with Meta. */
+ if (modifiers & dpyinfo->meta_mod_mask)
+ bzero (&compose_status, sizeof (compose_status));
+
+ #ifdef HAVE_X_I18N
+ if (FRAME_XIC (f))
+ {
+ Status status_return;
+
+ coding_system = Vlocale_coding_system;
+ nbytes = XmbLookupString (FRAME_XIC (f),
+ &event.xkey, copy_bufptr,
+ copy_bufsiz, &keysym,
+ &status_return);
+ if (status_return == XBufferOverflow)
+ {
+ copy_bufsiz = nbytes + 1;
+ copy_bufptr = (char *) alloca (copy_bufsiz);
+ nbytes = XmbLookupString (FRAME_XIC (f),
+ &event.xkey, copy_bufptr,
+ copy_bufsiz, &keysym,
+ &status_return);
+ }
+ /* Xutf8LookupString is a new but already deprecated interface.
-stef */
+ #if 0 && defined X_HAVE_UTF8_STRING
+ else if (status_return == XLookupKeySym)
+ { /* Try again but with utf-8. */
+ coding_system = Qutf_8;
+ nbytes = Xutf8LookupString (FRAME_XIC (f),
+ &event.xkey, copy_bufptr,
+ copy_bufsiz, &keysym,
+ &status_return);
+ if (status_return == XBufferOverflow)
+ {
+ copy_bufsiz = nbytes + 1;
+ copy_bufptr = (char *) alloca (copy_bufsiz);
+ nbytes = Xutf8LookupString (FRAME_XIC (f),
+ &event.xkey,
+ copy_bufptr,
+ copy_bufsiz, &keysym,
+ &status_return);
+ }
+ }
+ #endif
+
+ if (status_return == XLookupNone)
+ break;
+ else if (status_return == XLookupChars)
+ {
+ keysym = NoSymbol;
+ modifiers = 0;
+ }
+ else if (status_return != XLookupKeySym
+ && status_return != XLookupBoth)
+ abort ();
+ }
+ else
+ nbytes = XLookupString (&event.xkey, copy_bufptr,
+ copy_bufsiz, &keysym,
+ &compose_status);
+ #else
+ nbytes = XLookupString (&event.xkey, copy_bufptr,
+ copy_bufsiz, &keysym,
+ &compose_status);
+ #endif
+
+ orig_keysym = keysym;
+
+ if (numchars > 1)
+ {
+ Lisp_Object c;
+
+ /* First deal with keysyms which have defined
+ translations to characters. */
+ if (keysym >= 32 && keysym < 128)
+ /* Avoid explicitly decoding each ASCII character. */
+ {
+ bufp->kind = ASCII_KEYSTROKE_EVENT;
+ bufp->code = keysym;
+ XSETFRAME (bufp->frame_or_window, f);
+ bufp->arg = Qnil;
+ bufp->modifiers
+ = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
+ modifiers);
+ bufp->timestamp = event.xkey.time;
+ bufp++;
+ count++;
+ numchars--;
+ }
+ /* Now non-ASCII. */
+ else if (HASH_TABLE_P (Vx_keysym_table)
+ && (NATNUMP (c = Fgethash (make_number (keysym),
+ Vx_keysym_table,
+ Qnil))))
+ {
+ bufp->kind = (SINGLE_BYTE_CHAR_P (XFASTINT (c))
+ ? ASCII_KEYSTROKE_EVENT
+ : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
+ bufp->code = XFASTINT (c);
+ XSETFRAME (bufp->frame_or_window, f);
+ bufp->arg = Qnil;
+ bufp->modifiers
+ = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
+ modifiers);
+ bufp->timestamp = event.xkey.time;
+ bufp++;
+ count++;
+ numchars--;
+ }
+ /* Random non-modifier sorts of keysyms. */
+ else if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
+ || keysym == XK_Delete
+ #ifdef XK_ISO_Left_Tab
+ || (keysym >= XK_ISO_Left_Tab
+ && keysym <= XK_ISO_Enter)
+ #endif
+ || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
+ || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES
*/
+ #ifdef HPUX
+ /* This recognizes the "extended function
+ keys". It seems there's no cleaner way.
+ Test IsModifierKey to avoid handling
+ mode_switch incorrectly. */
+ || ((unsigned) (keysym) >= XK_Select
+ && (unsigned)(keysym) < XK_KP_Space)
+ #endif
+ #ifdef XK_dead_circumflex
+ || orig_keysym == XK_dead_circumflex
+ #endif
+ #ifdef XK_dead_grave
+ || orig_keysym == XK_dead_grave
+ #endif
+ #ifdef XK_dead_tilde
+ || orig_keysym == XK_dead_tilde
+ #endif
+ #ifdef XK_dead_diaeresis
+ || orig_keysym == XK_dead_diaeresis
+ #endif
+ #ifdef XK_dead_macron
+ || orig_keysym == XK_dead_macron
+ #endif
+ #ifdef XK_dead_degree
+ || orig_keysym == XK_dead_degree
+ #endif
+ #ifdef XK_dead_acute
+ || orig_keysym == XK_dead_acute
+ #endif
+ #ifdef XK_dead_cedilla
+ || orig_keysym == XK_dead_cedilla
+ #endif
+ #ifdef XK_dead_breve
+ || orig_keysym == XK_dead_breve
+ #endif
+ #ifdef XK_dead_ogonek
+ || orig_keysym == XK_dead_ogonek
+ #endif
+ #ifdef XK_dead_caron
+ || orig_keysym == XK_dead_caron
+ #endif
+ #ifdef XK_dead_doubleacute
+ || orig_keysym == XK_dead_doubleacute
+ #endif
+ #ifdef XK_dead_abovedot
+ || orig_keysym == XK_dead_abovedot
+ #endif
+ || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
+ || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
+ /* Any "vendor-specific" key is ok. */
+ || (orig_keysym & (1 << 28))
+ || (keysym != NoSymbol && nbytes == 0))
+ && ! (IsModifierKey (orig_keysym)
+ #ifndef HAVE_X11R5
+ #ifdef XK_Mode_switch
+ || ((unsigned)(orig_keysym) == XK_Mode_switch)
+ #endif
+ #ifdef XK_Num_Lock
+ || ((unsigned)(orig_keysym) == XK_Num_Lock)
+ #endif
+ #endif /* not HAVE_X11R5 */
+ /* The symbols from XK_ISO_Lock
+ to XK_ISO_Last_Group_Lock
+ don't have real modifiers but
+ should be treated similarly to
+ Mode_switch by Emacs. */
+ #if defined XK_ISO_Lock && defined XK_ISO_Last_Group_Lock
+ || ((unsigned)(orig_keysym)
+ >= XK_ISO_Lock
+ && (unsigned)(orig_keysym)
+ <= XK_ISO_Last_Group_Lock)
+ #endif
+ ))
+ {
+ if (temp_index == sizeof temp_buffer / sizeof (short))
+ temp_index = 0;
+ temp_buffer[temp_index++] = keysym;
+ /* make_lispy_event will convert this to a symbolic
+ key. */
+ bufp->kind = NON_ASCII_KEYSTROKE_EVENT;
+ bufp->code = keysym;
+ XSETFRAME (bufp->frame_or_window, f);
+ bufp->arg = Qnil;
+ bufp->modifiers
+ = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
+ modifiers);
+ bufp->timestamp = event.xkey.time;
+ bufp++;
+ count++;
+ numchars--;
+ }
+ else if (numchars > nbytes)
+ { /* Raw bytes, not keysym. */
+ register int i;
+ register int c;
+ int nchars, len;
+
+ /* The input should be decoded with `coding_system'
+ which depends on which X*LookupString function
+ we used just above and the locale. */
+ setup_coding_system (coding_system, &coding);
+ coding.src_multibyte = 0;
+ coding.dst_multibyte = 1;
+ /* The input is converted to events, thus we can't
+ handle composition. Anyway, there's no XIM that
+ gives us composition information. */
+ coding.common_flags &= ~CODING_ANNOTATION_MASK;
+
+ for (i = 0; i < nbytes; i++)
+ {
+ if (temp_index == (sizeof temp_buffer
+ / sizeof (short)))
+ temp_index = 0;
+ temp_buffer[temp_index++] = copy_bufptr[i];
+ }
+
+ {
+ /* Decode the input data. */
+ coding.destination = (unsigned char *) malloc (nbytes);
+ if (! coding.destination)
+ break;
+ coding.dst_bytes = nbytes;
+ coding.mode |= CODING_MODE_LAST_BLOCK;
+ decode_coding_c_string (&coding, copy_bufptr,
+ nbytes, Qnil);
+ nbytes = coding.produced;
+ nchars = coding.produced_char;
+ if (copy_bufsiz < nbytes)
+ {
+ copy_bufsiz = nbytes;
+ copy_bufptr = (char *) alloca (nbytes);
+ }
+ bcopy (coding.destination, copy_bufptr, nbytes);
+ free (coding.destination);
+ }
+
+ /* Convert the input data to a sequence of
+ character events. */
+ for (i = 0; i < nbytes; i += len)
+ {
+ if (nchars == nbytes)
+ c = copy_bufptr[i], len = 1;
+ else
+ c = STRING_CHAR_AND_LENGTH (copy_bufptr + i,
+ nbytes - i, len);
+
+ bufp->kind = (ASCII_CHAR_P (c)
+ ? ASCII_KEYSTROKE_EVENT
+ : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
+ bufp->code = c;
+ XSETFRAME (bufp->frame_or_window, f);
+ bufp->arg = Qnil;
+ bufp->modifiers
+ = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
+ modifiers);
+ bufp->timestamp = event.xkey.time;
+ bufp++;
+ }
+
+ count += nchars;
+ numchars -= nchars;
+
+ if (keysym == NoSymbol)
+ break;
+ }
+ else
+ abort ();
+ }
+ else
+ abort ();
+ }
+ #ifdef HAVE_X_I18N
+ /* Don't dispatch this event since XtDispatchEvent calls
+ XFilterEvent, and two calls in a row may freeze the
+ client. */
+ break;
+ #else
+ goto OTHER;
+ #endif
+
+ case KeyRelease:
+ #ifdef HAVE_X_I18N
+ /* Don't dispatch this event since XtDispatchEvent calls
+ XFilterEvent, and two calls in a row may freeze the
+ client. */
+ break;
+ #else
+ goto OTHER;
+ #endif
+
+ case EnterNotify:
+ {
+ int n;
+
+ n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
+ if (n > 0)
+ {
+ bufp += n, count += n, numchars -= n;
+ }
+
+ f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
+
+ #if 0
+ if (event.xcrossing.focus)
+ {
+ /* Avoid nasty pop/raise loops. */
+ if (f && (!(f->auto_raise)
+ || !(f->auto_lower)
+ || (event.xcrossing.time - enter_timestamp) > 500))
+ {
+ x_new_focus_frame (dpyinfo, f);
+ enter_timestamp = event.xcrossing.time;
+ }
+ }
+ else if (f == dpyinfo->x_focus_frame)
+ x_new_focus_frame (dpyinfo, 0);
+ #endif
+
+ /* EnterNotify counts as mouse movement,
+ so update things that depend on mouse position. */
+ if (f && !f->output_data.x->hourglass_p)
+ note_mouse_movement (f, &event.xmotion);
+ goto OTHER;
+ }
+
+ case FocusIn:
+ {
+ int n;
+
+ n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
+ if (n > 0)
+ {
+ bufp += n, count += n, numchars -= n;
+ }
+ }
+
+ goto OTHER;
+
+ case LeaveNotify:
+ {
+ int n;
+
+ n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
+ if (n > 0)
+ {
+ bufp += n, count += n, numchars -= n;
+ }
+ }
+
+ f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
+ if (f)
+ {
+ if (f == dpyinfo->mouse_face_mouse_frame)
+ {
+ /* If we move outside the frame, then we're
+ certainly no longer on any text in the frame. */
+ clear_mouse_face (dpyinfo);
+ dpyinfo->mouse_face_mouse_frame = 0;
+ }
+
+ /* Generate a nil HELP_EVENT to cancel a help-echo.
+ Do it only if there's something to cancel.
+ Otherwise, the startup message is cleared when
+ the mouse leaves the frame. */
+ if (any_help_event_p)
+ {
+ Lisp_Object frame;
+ int n;
+
+ XSETFRAME (frame, f);
+ help_echo_string = Qnil;
+ n = gen_help_event (bufp, numchars,
+ Qnil, frame, Qnil, Qnil, 0);
+ bufp += n, count += n, numchars -= n;
+ }
+
+ }
+ goto OTHER;
+
+ case FocusOut:
+ {
+ int n;
+
+ n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
+ if (n > 0)
+ {
+ bufp += n, count += n, numchars -= n;
+ }
+ }
+
+ goto OTHER;
+
+ case MotionNotify:
+ {
+ previous_help_echo_string = help_echo_string;
+ help_echo_string = help_echo_object = help_echo_window = Qnil;
+ help_echo_pos = -1;
+
+ if (dpyinfo->grabbed && last_mouse_frame
+ && FRAME_LIVE_P (last_mouse_frame))
+ f = last_mouse_frame;
+ else
+ f = x_window_to_frame (dpyinfo, event.xmotion.window);
+
+ if (dpyinfo->mouse_face_hidden)
+ {
+ dpyinfo->mouse_face_hidden = 0;
+ clear_mouse_face (dpyinfo);
+ }
+
+ if (f)
+ {
+
+ /* Generate SELECT_WINDOW_EVENTs when needed. */
+ if (mouse_autoselect_window)
+ {
+ Lisp_Object window;
+
+ window = window_from_coordinates (f,
+ event.xmotion.x,
event.xmotion.y,
+ 0, 0, 0, 0);
+
+ /* Window will be selected only when it is not selected now
and
+ last mouse movement event was not in it. Minibuffer window
+ will be selected iff it is active. */
+ if (WINDOWP(window)
+ && !EQ (window, last_window)
+ && !EQ (window, selected_window)
+ && numchars > 0)
+ {
+ bufp->kind = SELECT_WINDOW_EVENT;
+ bufp->frame_or_window = window;
+ bufp->arg = Qnil;
+ ++bufp, ++count, --numchars;
+ }
+
+ last_window=window;
+ }
+ note_mouse_movement (f, &event.xmotion);
+ }
+ else
+ {
+ #ifndef USE_TOOLKIT_SCROLL_BARS
+ struct scroll_bar *bar
+ = x_window_to_scroll_bar (event.xmotion.window);
+
+ if (bar)
+ x_scroll_bar_note_movement (bar, &event);
+ #endif /* USE_TOOLKIT_SCROLL_BARS */
+
+ /* If we move outside the frame, then we're
+ certainly no longer on any text in the frame. */
+ clear_mouse_face (dpyinfo);
+ }
+
+ /* If the contents of the global variable help_echo_string
+ has changed, generate a HELP_EVENT. */
+ if (!NILP (help_echo_string)
+ || !NILP (previous_help_echo_string))
+ {
+ Lisp_Object frame;
+ int n;
+
+ if (f)
+ XSETFRAME (frame, f);
+ else
+ frame = Qnil;
+
+ any_help_event_p = 1;
+ n = gen_help_event (bufp, numchars, help_echo_string, frame,
+ help_echo_window, help_echo_object,
+ help_echo_pos);
+ bufp += n, count += n, numchars -= n;
+ }
+
+ goto OTHER;
+ }
+
+ case ConfigureNotify:
+ f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
+ if (f)
+ {
+ #ifndef USE_X_TOOLKIT
+ #ifdef USE_GTK
+ xg_resize_widgets (f, event.xconfigure.width,
+ event.xconfigure.height);
+ #else /* not USE_GTK */
+ /* If there is a pending resize for fullscreen, don't
+ do this one, the right one will come later.
+ The toolkit version doesn't seem to need this, but we
+ need to reset it below. */
+ int dont_resize
+ = ((f->want_fullscreen & FULLSCREEN_WAIT)
+ && f->new_text_cols != 0);
+ int rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f,
event.xconfigure.height);
+ int columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f,
event.xconfigure.width);
+
+ if (dont_resize)
+ goto OTHER;
+
+ /* In the toolkit version, change_frame_size
+ is called by the code that handles resizing
+ of the EmacsFrame widget. */
+
+ /* Even if the number of character rows and columns has
+ not changed, the font size may have changed, so we need
+ to check the pixel dimensions as well. */
+ if (columns != FRAME_COLS (f)
+ || rows != FRAME_LINES (f)
+ || event.xconfigure.width != FRAME_PIXEL_WIDTH (f)
+ || event.xconfigure.height != FRAME_PIXEL_HEIGHT (f))
+ {
+ change_frame_size (f, rows, columns, 0, 1, 0);
+ SET_FRAME_GARBAGED (f);
+ cancel_mouse_face (f);
+ }
+ #endif /* not USE_GTK */
+ #endif
+
+ FRAME_PIXEL_WIDTH (f) = event.xconfigure.width;
+ FRAME_PIXEL_HEIGHT (f) = event.xconfigure.height;
+
+ #ifdef USE_GTK
+ /* GTK creates windows but doesn't map them.
+ Only get real positions and check fullscreen when mapped. */
+ if (FRAME_GTK_OUTER_WIDGET (f)
+ && GTK_WIDGET_MAPPED (FRAME_GTK_OUTER_WIDGET (f)))
+ #endif
+ {
+ /* What we have now is the position of Emacs's own window.
+ Convert that to the position of the window manager window. */
+ x_real_positions (f, &f->left_pos, &f->top_pos);
+
+ x_check_fullscreen_move (f);
+ if (f->want_fullscreen & FULLSCREEN_WAIT)
+ f->want_fullscreen &= ~(FULLSCREEN_WAIT|FULLSCREEN_BOTH);
+ }
+
+ #ifdef HAVE_X_I18N
+ if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea))
+ xic_set_statusarea (f);
+ #endif
+
+ if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO
(f)->root_window)
+ {
+ /* Since the WM decorations come below top_pos now,
+ we must put them below top_pos in the future. */
+ f->win_gravity = NorthWestGravity;
+ x_wm_set_size_hint (f, (long) 0, 0);
+ }
+ }
+ goto OTHER;
+
+ case ButtonRelease:
+ case ButtonPress:
+ {
+ /* 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;
+ int tool_bar_p = 0;
+
+ emacs_event.kind = NO_EVENT;
+ bzero (&compose_status, sizeof (compose_status));
+
+ if (dpyinfo->grabbed
+ && last_mouse_frame
+ && FRAME_LIVE_P (last_mouse_frame))
+ f = last_mouse_frame;
+ else
+ f = x_window_to_frame (dpyinfo, event.xbutton.window);
+
+ if (f)
+ {
+ /* Is this in the tool-bar? */
+ if (WINDOWP (f->tool_bar_window)
+ && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)))
+ {
+ Lisp_Object window;
+ int x = event.xbutton.x;
+ int y = event.xbutton.y;
+
+ window = window_from_coordinates (f, x, y, 0, 0, 0, 1);
+ if (EQ (window, f->tool_bar_window))
+ {
+ if (event.xbutton.type == ButtonPress)
+ handle_tool_bar_click (f, x, y, 1, 0);
+ else
+ handle_tool_bar_click (f, x, y, 0,
+ x_x_to_emacs_modifiers (dpyinfo,
+
event.xbutton.state));
+ tool_bar_p = 1;
+ }
+ }
+
+ if (!tool_bar_p)
+ if (!dpyinfo->x_focus_frame
+ || f == dpyinfo->x_focus_frame)
+ {
+ #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
+ if (! popup_activated ())
+ #endif
+ construct_mouse_click (&emacs_event, &event, f);
+ }
+ }
+ else
+ {
+ struct scroll_bar *bar
+ = x_window_to_scroll_bar (event.xbutton.window);
+
+ #ifdef USE_TOOLKIT_SCROLL_BARS
+ /* Make the "Ctrl-Mouse-2 splits window" work for toolkit
+ scroll bars. */
+ if (bar && event.xbutton.state & ControlMask)
+ {
+ x_scroll_bar_handle_click (bar, &event, &emacs_event);
+ *finish = X_EVENT_DROP;
+ }
+ #else /* not USE_TOOLKIT_SCROLL_BARS */
+ if (bar)
+ x_scroll_bar_handle_click (bar, &event, &emacs_event);
+ #endif /* not USE_TOOLKIT_SCROLL_BARS */
+ }
+
+ if (event.type == ButtonPress)
+ {
+ dpyinfo->grabbed |= (1 << event.xbutton.button);
+ last_mouse_frame = f;
+ /* Ignore any mouse motion that happened
+ before this event; any subsequent mouse-movement
+ Emacs events should reflect only motion after
+ the ButtonPress. */
+ if (f != 0)
+ f->mouse_moved = 0;
+
+ if (!tool_bar_p)
+ last_tool_bar_item = -1;
+ }
+ else
+ dpyinfo->grabbed &= ~(1 << event.xbutton.button);
+
+ if (numchars >= 1 && emacs_event.kind != NO_EVENT)
+ {
+ bcopy (&emacs_event, bufp, sizeof (struct input_event));
+ bufp++;
+ count++;
+ numchars--;
+ }
+
+ #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
+ f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
+ /* For a down-event in the menu bar,
+ don't pass it to Xt right now.
+ Instead, save it away
+ and we will pass it to Xt from kbd_buffer_get_event.
+ That way, we can run some Lisp code first. */
+ if (
+ #ifdef USE_GTK
+ ! popup_activated ()
+ &&
+ #endif
+ f && event.type == ButtonPress
+ /* Verify the event is really within the menu bar
+ and not just sent to it due to grabbing. */
+ && event.xbutton.x >= 0
+ && event.xbutton.x < FRAME_PIXEL_WIDTH (f)
+ && event.xbutton.y >= 0
+ && event.xbutton.y < f->output_data.x->menubar_height
+ && event.xbutton.same_screen)
+ {
+ SET_SAVED_BUTTON_EVENT;
+ XSETFRAME (last_mouse_press_frame, f);
+ #ifdef USE_GTK
+ *finish = X_EVENT_DROP;
+ #endif
+ }
+ else if (event.type == ButtonPress)
+ {
+ last_mouse_press_frame = Qnil;
+ goto OTHER;
+ }
+
+ #ifdef USE_MOTIF /* This should do not harm for Lucid,
+ but I am trying to be cautious. */
+ else if (event.type == ButtonRelease)
+ {
+ if (!NILP (last_mouse_press_frame))
+ {
+ f = XFRAME (last_mouse_press_frame);
+ if (f->output_data.x)
+ SET_SAVED_BUTTON_EVENT;
+ }
+ else
+ goto OTHER;
+ }
+ #endif /* USE_MOTIF */
+ else
+ goto OTHER;
+ #endif /* USE_X_TOOLKIT || USE_GTK */
+ }
+ break;
+
+ case CirculateNotify:
+ goto OTHER;
+
+ case CirculateRequest:
+ goto OTHER;
+
+ case VisibilityNotify:
+ goto OTHER;
+
+ case MappingNotify:
+ /* Someone has changed the keyboard mapping - update the
+ local cache. */
+ switch (event.xmapping.request)
+ {
+ case MappingModifier:
+ x_find_modifier_meanings (dpyinfo);
+ /* This is meant to fall through. */
+ case MappingKeyboard:
+ XRefreshKeyboardMapping (&event.xmapping);
+ }
+ goto OTHER;
+
+ default:
+ OTHER:
+ #ifdef USE_X_TOOLKIT
+ BLOCK_INPUT;
+ if (*finish != X_EVENT_DROP)
+ XtDispatchEvent (&event);
+ UNBLOCK_INPUT;
+ #endif /* USE_X_TOOLKIT */
+ break;
+ }
+
+ goto ret;
+
+ out:
+ *finish = X_EVENT_GOTO_OUT;
+
+ ret:
+ *bufp_r = bufp;
+ *numcharsp = numchars;
+ *eventp = event;
+
+ return count;
+ }
+
+
+ /* Handles the XEvent EVENT on display DISPLAY.
+ This is used for event loops outside the normal event handling,
+ i.e. looping while a popup menu or a dialog is posted.
+
+ Returns the value handle_one_xevent sets in the finish argument. */
+ int
+ x_dispatch_event (event, display)
+ XEvent *event;
+ Display *display;
+ {
+ struct x_display_info *dpyinfo;
+ struct input_event bufp[10];
+ struct input_event *bufpp;
+ int numchars = 10;
+ int finish = X_EVENT_NORMAL;
+
+ for (bufpp = bufp; bufpp != bufp + 10; bufpp++)
+ EVENT_INIT (*bufpp);
+ bufpp = bufp;
+
+ for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
+ if (dpyinfo->display == display)
+ break;
+
+ if (dpyinfo)
+ {
+ int i, events;
+ events = handle_one_xevent (dpyinfo,
+ event,
+ &bufpp,
+ &numchars,
+ &finish);
+ for (i = 0; i < events; ++i)
+ kbd_buffer_store_event (&bufp[i]);
+ }
+
+ return finish;
+ }
+
+
+ /* 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'.
+
+ EXPECTED is nonzero if the caller knows input is available. */
+
+ static int
+ XTread_socket (sd, bufp, numchars, expected)
+ register int sd;
+ /* register */ struct input_event *bufp;
+ /* register */ int numchars;
+ int expected;
+ {
+ int count = 0;
+ XEvent event;
+ int event_found = 0;
+ struct x_display_info *dpyinfo;
+
+ if (interrupt_input_blocked)
+ {
+ interrupt_input_pending = 1;
+ return -1;
+ }
+
+ interrupt_input_pending = 0;
+ BLOCK_INPUT;
+
+ /* So people can tell when we have read the available input. */
+ input_signal_count++;
+
+ if (numchars <= 0)
+ abort (); /* Don't think this happens. */
+
+ ++handling_signal;
+
+ /* Find the display we are supposed to read input for.
+ It's the one communicating on descriptor SD. */
+ for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
+ {
+ #if 0 /* This ought to be unnecessary; let's verify it. */
+ #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 signaling EWOULDBLOCK,
+ a read returns 0, which Xlib interprets as equivalent to EPIPE. */
+ fcntl (dpyinfo->connection, F_SETFL, 0);
+ #endif /* ! defined (FIOSNBIO) */
+ #endif
+
+ #if 0 /* This code can't be made to work, with multiple displays,
+ and appears not to be used on any system any more.
+ Also keyboard.c doesn't turn O_NDELAY on and off
+ for X connections. */
+ #ifndef SIGIO
+ #ifndef HAVE_SELECT
+ if (! (fcntl (dpyinfo->connection, F_GETFL, 0) & O_NDELAY))
+ {
+ extern int read_alarm_should_throw;
+ read_alarm_should_throw = 1;
+ XPeekEvent (dpyinfo->display, &event);
+ read_alarm_should_throw = 0;
+ }
+ #endif /* HAVE_SELECT */
+ #endif /* SIGIO */
+ #endif
+
+ /* For debugging, this gives a way to fake an I/O error. */
+ if (dpyinfo == XTread_socket_fake_io_error)
+ {
+ XTread_socket_fake_io_error = 0;
+ x_io_error_quitter (dpyinfo->display);
+ }
+
+ #ifdef HAVE_X_SM
+ BLOCK_INPUT;
+ count += x_session_check_input (bufp, &numchars);
+ UNBLOCK_INPUT;
+ #endif
+
+ #ifdef USE_GTK
+ /* For GTK we must use the GTK event loop. But XEvents gets passed
+ to our filter function above, and then to the big event switch.
+ We use a bunch of globals to communicate with our filter function,
+ that is kind of ugly, but it works. */
+ current_dpyinfo = dpyinfo;
+
+ while (gtk_events_pending ())
+ {
+ current_count = count;
+ current_numcharsp = &numchars;
+ current_bufp = &bufp;
+
+ gtk_main_iteration ();
+
+ count = current_count;
+ current_bufp = 0;
+ current_numcharsp = 0;
+
+ if (current_finish == X_EVENT_GOTO_OUT)
+ goto out;
+ }
+
+ #else /* not USE_GTK */
+ while (XPending (dpyinfo->display))
+ {
+ int finish;
+
+ XNextEvent (dpyinfo->display, &event);
+
+ #ifdef HAVE_X_I18N
+ /* Filter events for the current X input method. */
+ if (x_filter_event (dpyinfo, &event))
+ break;
+ #endif
+ event_found = 1;
+
+ count += handle_one_xevent (dpyinfo,
+ &event,
+ &bufp,
+ &numchars,
+ &finish);
+
+ if (finish == X_EVENT_GOTO_OUT)
+ goto out;
+ }
+ #endif /* USE_GTK */
+ }
+
+ out:;
+
+ /* On some systems, an X bug causes Emacs to get no more events
+ when the window is destroyed. Detect that. (1994.) */
+ if (! event_found)
+ {
+ /* Emacs and the X Server eats up CPU time if XNoOp is done every time.
+ One XNOOP in 100 loops will make Emacs terminate.
+ B. Bretthauer, 1994 */
+ x_noop_count++;
+ if (x_noop_count >= 100)
+ {
+ x_noop_count=0;
+
+ if (next_noop_dpyinfo == 0)
+ next_noop_dpyinfo = x_display_list;
+
+ XNoOp (next_noop_dpyinfo->display);
+
+ /* Each time we get here, cycle through the displays now open. */
+ next_noop_dpyinfo = next_noop_dpyinfo->next;
+ }
+ }
+
+ /* If the focus was just given to an auto-raising frame,
+ raise it now. */
+ /* ??? This ought to be able to handle more than one such frame. */
+ if (pending_autoraise_frame)
+ {
+ x_raise_frame (pending_autoraise_frame);
+ pending_autoraise_frame = 0;
+ }
+
+ UNBLOCK_INPUT;
+ --handling_signal;
+ return count;
+ }
+
+
+
+
+ /***********************************************************************
+ Text Cursor
+ ***********************************************************************/
+
+ /* Set clipping for output in glyph row ROW. W is the window in which
+ we operate. GC is the graphics context to set clipping in.
+
+ ROW may be a text row or, e.g., a mode line. Text rows must be
+ clipped to the interior of the window dedicated to text display,
+ mode lines must be clipped to the whole window. */
+
+ static void
+ x_clip_to_row (w, row, gc)
+ struct window *w;
+ struct glyph_row *row;
+ GC gc;
+ {
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ XRectangle clip_rect;
+ int window_y, window_width;
+
+ window_box (w, -1, 0, &window_y, &window_width, 0);
+
+ clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
+ clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
+ clip_rect.y = max (clip_rect.y, window_y);
+ clip_rect.width = window_width;
+ clip_rect.height = row->visible_height;
+
+ XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
+ }
+
+
+ /* Draw a hollow box cursor on window W in glyph row ROW. */
+
+ static void
+ x_draw_hollow_cursor (w, row)
+ struct window *w;
+ struct glyph_row *row;
+ {
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ Display *dpy = FRAME_X_DISPLAY (f);
+ int x, y, wd, h;
+ XGCValues xgcv;
+ struct glyph *cursor_glyph;
+ GC gc;
+
+ /* Compute frame-relative coordinates from window-relative
+ coordinates. */
+ x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
+ y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
+ + row->ascent - w->phys_cursor_ascent);
+ h = row->height - 1;
+
+ /* Get the glyph the cursor is on. If we can't tell because
+ the current matrix is invalid or such, give up. */
+ cursor_glyph = get_phys_cursor_glyph (w);
+ if (cursor_glyph == NULL)
+ return;
+
+ /* Compute the width of the rectangle to draw. If on a stretch
+ glyph, and `x-stretch-block-cursor' is nil, don't draw a
+ rectangle as wide as the glyph, but use a canonical character
+ width instead. */
+ wd = cursor_glyph->pixel_width - 1;
+ if (cursor_glyph->type == STRETCH_GLYPH
+ && !x_stretch_cursor_p)
+ wd = min (FRAME_COLUMN_WIDTH (f), wd);
+ w->phys_cursor_width = wd;
+
+ /* The foreground of cursor_gc is typically the same as the normal
+ background color, which can cause the cursor box to be invisible. */
+ xgcv.foreground = f->output_data.x->cursor_pixel;
+ if (dpyinfo->scratch_cursor_gc)
+ XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
+ else
+ dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
+ GCForeground, &xgcv);
+ gc = dpyinfo->scratch_cursor_gc;
+
+ /* Set clipping, draw the rectangle, and reset clipping again. */
+ x_clip_to_row (w, row, gc);
+ XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
+ XSetClipMask (dpy, gc, None);
+ }
+
+
+ /* Draw a bar cursor on window W in glyph row ROW.
+
+ Implementation note: One would like to draw a bar cursor with an
+ angle equal to the one given by the font property XA_ITALIC_ANGLE.
+ Unfortunately, I didn't find a font yet that has this property set.
+ --gerd. */
+
+ static void
+ x_draw_bar_cursor (w, row, width, kind)
+ struct window *w;
+ struct glyph_row *row;
+ int width;
+ enum text_cursor_kinds kind;
+ {
+ struct frame *f = XFRAME (w->frame);
+ struct glyph *cursor_glyph;
+
+ /* If cursor is out of bounds, don't draw garbage. This can happen
+ in mini-buffer windows when switching between echo area glyphs
+ and mini-buffer. */
+ cursor_glyph = get_phys_cursor_glyph (w);
+ if (cursor_glyph == NULL)
+ return;
+
+ /* If on an image, draw like a normal cursor. That's usually better
+ visible than drawing a bar, esp. if the image is large so that
+ the bar might not be in the window. */
+ if (cursor_glyph->type == IMAGE_GLYPH)
+ {
+ struct glyph_row *row;
+ row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
+ draw_phys_cursor_glyph (w, row, DRAW_CURSOR);
+ }
+ else
+ {
+ Display *dpy = FRAME_X_DISPLAY (f);
+ Window window = FRAME_X_WINDOW (f);
+ GC gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
+ unsigned long mask = GCForeground | GCBackground | GCGraphicsExposures;
+ struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
+ XGCValues xgcv;
+
+ /* If the glyph's background equals the color we normally draw
+ the bar cursor in, the bar cursor in its normal color is
+ invisible. Use the glyph's foreground color instead in this
+ case, on the assumption that the glyph's colors are chosen so
+ that the glyph is legible. */
+ if (face->background == f->output_data.x->cursor_pixel)
+ xgcv.background = xgcv.foreground = face->foreground;
+ else
+ xgcv.background = xgcv.foreground = f->output_data.x->cursor_pixel;
+ xgcv.graphics_exposures = 0;
+
+ if (gc)
+ XChangeGC (dpy, gc, mask, &xgcv);
+ else
+ {
+ gc = XCreateGC (dpy, window, mask, &xgcv);
+ FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
+ }
+
+ if (width < 0)
+ width = FRAME_CURSOR_WIDTH (f);
+ width = min (cursor_glyph->pixel_width, width);
+
+ w->phys_cursor_width = width;
+ x_clip_to_row (w, row, gc);
+
+ if (kind == BAR_CURSOR)
+ XFillRectangle (dpy, window, gc,
+ WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
+ WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
+ width, row->height);
+ else
+ XFillRectangle (dpy, window, gc,
+ WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
+ WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
+ row->height - width),
+ cursor_glyph->pixel_width,
+ width);
+
+ XSetClipMask (dpy, gc, None);
+ }
+ }
+
+
+ /* RIF: Define cursor CURSOR on frame F. */
+
+ static void
+ x_define_frame_cursor (f, cursor)
+ struct frame *f;
+ Cursor cursor;
+ {
+ XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
+ }
+
+
+ /* RIF: Clear area on frame F. */
+
+ static void
+ x_clear_frame_area (f, x, y, width, height)
+ struct frame *f;
+ int x, y, width, height;
+ {
+ x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ x, y, width, height, False);
+ }
+
+
+ /* RIF: Draw cursor on window W. */
+
+ static void
+ x_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p,
active_p)
+ struct window *w;
+ struct glyph_row *glyph_row;
+ int x, y;
+ int cursor_type, cursor_width;
+ int on_p, active_p;
+ {
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+
+ if (on_p)
+ {
+ w->phys_cursor_type = cursor_type;
+ w->phys_cursor_on_p = 1;
+
+ switch (cursor_type)
+ {
+ case HOLLOW_BOX_CURSOR:
+ x_draw_hollow_cursor (w, glyph_row);
+ break;
+
+ case FILLED_BOX_CURSOR:
+ draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
+ break;
+
+ case BAR_CURSOR:
+ x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
+ break;
+
+ case HBAR_CURSOR:
+ x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
+ break;
+
+ case NO_CURSOR:
+ w->phys_cursor_width = 0;
+ break;
+
+ default:
+ abort ();
+ }
+
+ #ifdef HAVE_X_I18N
+ if (w == XWINDOW (f->selected_window))
+ if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMPreeditPosition))
+ xic_set_preeditarea (w, x, y);
+ #endif
+ }
+
+ #ifndef XFlush
+ if (updating_frame != f)
+ XFlush (FRAME_X_DISPLAY (f));
+ #endif
+ }
+
+
+ /* Icons. */
+
+ /* Make the x-window of frame F use the gnu icon bitmap. */
+
+ int
+ x_bitmap_icon (f, file)
+ struct frame *f;
+ Lisp_Object file;
+ {
+ int bitmap_id;
+
+ if (FRAME_X_WINDOW (f) == 0)
+ return 1;
+
+ /* Free up our existing icon bitmap and mask if any. */
+ if (f->output_data.x->icon_bitmap > 0)
+ x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
+ f->output_data.x->icon_bitmap = 0;
+
+ if (STRINGP (file))
+ {
+ #ifdef USE_GTK
+ /* Use gtk_window_set_icon_from_file() if available,
+ It's not restricted to bitmaps */
+ if (xg_set_icon(f, file))
+ return 0;
+ #endif /* USE_GTK */
+ bitmap_id = x_create_bitmap_from_file (f, file);
+ x_create_bitmap_mask(f, bitmap_id);
+ }
+ else
+ {
+ /* Create the GNU bitmap and mask if necessary. */
+ if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0)
+ {
+ FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id
+ = x_create_bitmap_from_data (f, gnu_bits,
+ gnu_width, gnu_height);
+ x_create_bitmap_mask(f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
+ }
+
+ /* The first time we create the GNU bitmap and mask,
+ this increments the ref-count one extra time.
+ As a result, the GNU bitmap and mask are never freed.
+ That way, we don't have to worry about allocating it again. */
+ x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
+
+ bitmap_id = FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id;
+ }
+
+ x_wm_set_icon_pixmap (f, bitmap_id);
+ f->output_data.x->icon_bitmap = bitmap_id;
+
+ return 0;
+ }
+
+
+ /* Make the x-window of frame F use a rectangle with text.
+ Use ICON_NAME as the text. */
+
+ int
+ x_text_icon (f, icon_name)
+ struct frame *f;
+ char *icon_name;
+ {
+ if (FRAME_X_WINDOW (f) == 0)
+ return 1;
+
+ #ifdef HAVE_X11R4
+ {
+ XTextProperty text;
+ text.value = (unsigned char *) icon_name;
+ text.encoding = XA_STRING;
+ text.format = 8;
+ text.nitems = strlen (icon_name);
+ XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), &text);
+ }
+ #else /* not HAVE_X11R4 */
+ XSetIconName (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), icon_name);
+ #endif /* not HAVE_X11R4 */
+
+ if (f->output_data.x->icon_bitmap > 0)
+ x_destroy_bitmap (f, f->output_data.x->icon_bitmap);
+ f->output_data.x->icon_bitmap = 0;
+ x_wm_set_icon_pixmap (f, 0);
+
+ return 0;
+ }
+
+ #define X_ERROR_MESSAGE_SIZE 200
+
+ /* If non-nil, this should be a string.
+ It means catch X errors and store the error message in this string. */
+
+ static Lisp_Object x_error_message_string;
+
+ /* An X error handler which stores the error message in
+ x_error_message_string. This is called from x_error_handler if
+ x_catch_errors is in effect. */
+
+ static void
+ x_error_catcher (display, error)
+ Display *display;
+ XErrorEvent *error;
+ {
+ XGetErrorText (display, error->error_code,
+ SDATA (x_error_message_string),
+ X_ERROR_MESSAGE_SIZE);
+ }
+
+ /* Begin trapping X errors for display DPY. Actually we trap X errors
+ for all displays, but DPY should be the display you are actually
+ operating on.
+
+ After calling this function, X protocol errors no longer cause
+ Emacs to exit; instead, they are recorded in the string
+ stored in x_error_message_string.
+
+ Calling x_check_errors signals an Emacs error if an X error has
+ occurred since the last call to x_catch_errors or x_check_errors.
+
+ Calling x_uncatch_errors resumes the normal error handling. */
+
+ void x_check_errors ();
+ static Lisp_Object x_catch_errors_unwind ();
+
+ int
+ x_catch_errors (dpy)
+ Display *dpy;
+ {
+ int count = SPECPDL_INDEX ();
+
+ /* Make sure any errors from previous requests have been dealt with. */
+ XSync (dpy, False);
+
+ record_unwind_protect (x_catch_errors_unwind,
+ Fcons (make_save_value (dpy, 0),
+ x_error_message_string));
+
+ x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
+ SSET (x_error_message_string, 0, 0);
+
+ return count;
+ }
+
+ /* Unbind the binding that we made to check for X errors. */
+
+ static Lisp_Object
+ x_catch_errors_unwind (old_val)
+ Lisp_Object old_val;
+ {
+ Lisp_Object first;
+
+ first = XCAR (old_val);
+
+ XSync (XSAVE_VALUE (first)->pointer, False);
+
+ x_error_message_string = XCDR (old_val);
+ return Qnil;
+ }
+
+ /* If any X protocol errors have arrived since the last call to
+ x_catch_errors or x_check_errors, signal an Emacs error using
+ sprintf (a buffer, FORMAT, the x error message text) as the text. */
+
+ void
+ x_check_errors (dpy, format)
+ Display *dpy;
+ char *format;
+ {
+ /* Make sure to catch any errors incurred so far. */
+ XSync (dpy, False);
+
+ if (SREF (x_error_message_string, 0))
+ error (format, SDATA (x_error_message_string));
+ }
+
+ /* Nonzero if we had any X protocol errors
+ since we did x_catch_errors on DPY. */
+
+ int
+ x_had_errors_p (dpy)
+ Display *dpy;
+ {
+ /* Make sure to catch any errors incurred so far. */
+ XSync (dpy, False);
+
+ return SREF (x_error_message_string, 0) != 0;
+ }
+
+ /* Forget about any errors we have had, since we did x_catch_errors on DPY.
*/
+
+ void
+ x_clear_errors (dpy)
+ Display *dpy;
+ {
+ SSET (x_error_message_string, 0, 0);
+ }
+
+ /* Stop catching X protocol errors and let them make Emacs die.
+ DPY should be the display that was passed to x_catch_errors.
+ COUNT should be the value that was returned by
+ the corresponding call to x_catch_errors. */
+
+ void
+ x_uncatch_errors (dpy, count)
+ Display *dpy;
+ int count;
+ {
+ unbind_to (count, Qnil);
+ }
+
+ #if 0
+ static unsigned int x_wire_count;
+ x_trace_wire ()
+ {
+ fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
+ }
+ #endif /* ! 0 */
+
+
+ /* Handle SIGPIPE, which can happen when the connection to a server
+ simply goes away. SIGPIPE is handled by x_connection_signal.
+ Don't need to do anything, because the write which caused the
+ SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
+ which will do the appropriate cleanup for us. */
+
+ static SIGTYPE
+ x_connection_signal (signalnum) /* If we don't have an argument, */
+ int signalnum; /* some compilers complain in signal calls. */
+ {
+ #ifdef USG
+ /* USG systems forget handlers when they are used;
+ must reestablish each time */
+ signal (signalnum, x_connection_signal);
+ #endif /* USG */
+ }
+
+
+ /************************************************************************
+ Handling X errors
+ ************************************************************************/
+
+ /* Error message passed to x_connection_closed. */
+
+ static char *error_msg;
+
+ /* Function installed as fatal_error_signal_hook in
+ x_connection_closed. Print the X error message, and exit normally,
+ instead of dumping core when XtCloseDisplay fails. */
+
+ static void
+ x_fatal_error_signal ()
+ {
+ fprintf (stderr, "%s\n", error_msg);
+ exit (70);
+ }
+
+ /* Handle the loss of connection to display DPY. ERROR_MESSAGE is
+ the text of an error message that lead to the connection loss. */
+
+ static SIGTYPE
+ x_connection_closed (dpy, error_message)
+ Display *dpy;
+ char *error_message;
+ {
+ struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
+ Lisp_Object frame, tail;
+ int count;
+
+ error_msg = (char *) alloca (strlen (error_message) + 1);
+ strcpy (error_msg, error_message);
+ handling_signal = 0;
+
+ /* Prevent being called recursively because of an error condition
+ below. Otherwise, we might end up with printing ``can't find per
+ display information'' in the recursive call instead of printing
+ the original message here. */
+ count = x_catch_errors (dpy);
+
+ /* We have to close the display to inform Xt that it doesn't
+ exist anymore. If we don't, Xt will continue to wait for
+ events from the display. As a consequence, a sequence of
+
+ M-x make-frame-on-display RET :1 RET
+ ...kill the new frame, so that we get an IO error...
+ M-x make-frame-on-display RET :1 RET
+
+ will indefinitely wait in Xt for events for display `:1', opened
+ in the first class to make-frame-on-display.
+
+ Closing the display is reported to lead to a bus error on
+ OpenWindows in certain situations. I suspect that is a bug
+ in OpenWindows. I don't know how to cicumvent it here. */
+
+ #ifdef USE_X_TOOLKIT
+ /* If DPYINFO is null, this means we didn't open the display
+ in the first place, so don't try to close it. */
+ if (dpyinfo)
+ {
+ extern void (*fatal_error_signal_hook) P_ ((void));
+ fatal_error_signal_hook = x_fatal_error_signal;
+ XtCloseDisplay (dpy);
+ fatal_error_signal_hook = NULL;
+ }
+ #endif
+
+ /* Indicate that this display is dead. */
+ if (dpyinfo)
+ dpyinfo->display = 0;
+
+ /* First delete frames whose mini-buffers are on frames
+ that are on the dead display. */
+ FOR_EACH_FRAME (tail, frame)
+ {
+ Lisp_Object minibuf_frame;
+ minibuf_frame
+ = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame))));
+ if (FRAME_X_P (XFRAME (frame))
+ && FRAME_X_P (XFRAME (minibuf_frame))
+ && ! EQ (frame, minibuf_frame)
+ && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo)
+ Fdelete_frame (frame, Qt);
+ }
+
+ /* Now delete all remaining frames on the dead display.
+ We are now sure none of these is used as the mini-buffer
+ for another frame that we need to delete. */
+ FOR_EACH_FRAME (tail, frame)
+ if (FRAME_X_P (XFRAME (frame))
+ && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
+ {
+ /* Set this to t so that Fdelete_frame won't get confused
+ trying to find a replacement. */
+ FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt;
+ Fdelete_frame (frame, Qt);
+ }
+
+ if (dpyinfo)
+ x_delete_display (dpyinfo);
+
+ x_uncatch_errors (dpy, count);
+
+ if (x_display_list == 0)
+ {
+ fprintf (stderr, "%s\n", error_msg);
+ shut_down_emacs (0, 0, Qnil);
+ exit (70);
+ }
+
+ /* Ordinary stack unwind doesn't deal with these. */
+ #ifdef SIGIO
+ sigunblock (sigmask (SIGIO));
+ #endif
+ sigunblock (sigmask (SIGALRM));
+ TOTALLY_UNBLOCK_INPUT;
+
+ clear_waiting_for_input ();
+ error ("%s", error_msg);
+ }
+
+
+ /* This is the usual handler for X protocol errors.
+ It kills all frames on the display that we got the error for.
+ If that was the only one, it prints an error message and kills Emacs. */
+
+ static void
+ x_error_quitter (display, error)
+ Display *display;
+ XErrorEvent *error;
+ {
+ char buf[256], buf1[356];
+
+ /* Note that there is no real way portable across R3/R4 to get the
+ original error handler. */
+
+ XGetErrorText (display, error->error_code, buf, sizeof (buf));
+ sprintf (buf1, "X protocol error: %s on protocol request %d",
+ buf, error->request_code);
+ x_connection_closed (display, buf1);
+ }
+
+
+ /* This is the first-level handler for X protocol errors.
+ It calls x_error_quitter or x_error_catcher. */
+
+ static int
+ x_error_handler (display, error)
+ Display *display;
+ XErrorEvent *error;
+ {
+ if (! NILP (x_error_message_string))
+ x_error_catcher (display, error);
+ else
+ x_error_quitter (display, error);
+ return 0;
+ }
+
+ /* This is the handler for X IO errors, always.
+ It kills all frames on the display that we lost touch with.
+ If that was the only one, it prints an error message and kills Emacs. */
+
+ static int
+ x_io_error_quitter (display)
+ Display *display;
+ {
+ char buf[256];
+
+ sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
+ x_connection_closed (display, buf);
+ return 0;
+ }
+
+ /* Changing the font of the frame. */
+
+ /* Give frame F the font named FONTNAME as its default font, and
+ return the full name of that font. FONTNAME may be a wildcard
+ pattern; in that case, we choose some font that fits the pattern.
+ The return value shows which font we chose. */
+
+ Lisp_Object
+ x_new_font (f, fontname)
+ struct frame *f;
+ register char *fontname;
+ {
+ struct font_info *fontp
+ = FS_LOAD_FONT (f, fontname);
+
+ if (!fontp)
+ return Qnil;
+
+ if (FRAME_FONT (f) == (XFontStruct *) (fontp->font))
+ /* This font is already set in frame F. There's nothing more to
+ do. */
+ return build_string (fontp->full_name);
+
+ FRAME_FONT (f) = (XFontStruct *) (fontp->font);
+ FRAME_BASELINE_OFFSET (f) = fontp->baseline_offset;
+ FRAME_FONTSET (f) = -1;
+
+ FRAME_COLUMN_WIDTH (f) = FONT_WIDTH (FRAME_FONT (f));
+ FRAME_LINE_HEIGHT (f) = FONT_HEIGHT (FRAME_FONT (f));
+
+ compute_fringe_widths (f, 1);
+
+ /* Compute the scroll bar width in character columns. */
+ if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
+ {
+ int wid = FRAME_COLUMN_WIDTH (f);
+ FRAME_CONFIG_SCROLL_BAR_COLS (f)
+ = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid-1) / wid;
+ }
+ else
+ {
+ int wid = FRAME_COLUMN_WIDTH (f);
+ FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
+ }
+
+ /* Now make the frame display the given font. */
+ if (FRAME_X_WINDOW (f) != 0)
+ {
+ XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
+ FRAME_FONT (f)->fid);
+ XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
+ FRAME_FONT (f)->fid);
+ XSetFont (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
+ FRAME_FONT (f)->fid);
+
+ /* Don't change the size of a tip frame; there's no point in
+ doing it because it's done in Fx_show_tip, and it leads to
+ problems because the tip frame has no widget. */
+ if (NILP (tip_frame) || XFRAME (tip_frame) != f)
+ x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
+ }
+
+ return build_string (fontp->full_name);
+ }
+
+ /* Give frame F the fontset named FONTSETNAME as its default fontset,
+ and return the full name of that fontset. FONTSETNAME may be a
+ wildcard pattern; in that case, we choose some fontset that fits
+ the pattern. FONTSETNAME may be a font name for ASCII characters;
+ in that case, we create a fontset from that font name.
+
+ The return value shows which fontset we chose.
+ If FONTSETNAME specifies the default fontset, return Qt.
+ If an ASCII font in the specified fontset can't be loaded, return
+ Qnil. */
+
+ Lisp_Object
+ x_new_fontset (f, fontsetname)
+ struct frame *f;
+ Lisp_Object fontsetname;
+ {
+ int fontset = fs_query_fontset (fontsetname, 0);
+ Lisp_Object result;
+
+ if (fontset > 0 && f->output_data.x->fontset == fontset)
+ /* This fontset is already set in frame F. There's nothing more
+ to do. */
+ return fontset_name (fontset);
+ else if (fontset == 0)
+ /* The default fontset can't be the default font. */
+ return Qt;
+
+ if (fontset > 0)
+ result = x_new_font (f, (SDATA (fontset_ascii (fontset))));
+ else
+ result = x_new_font (f, SDATA (fontsetname));
+
+ if (!STRINGP (result))
+ /* Can't load ASCII font. */
+ return Qnil;
+
+ if (fontset < 0)
+ fontset = new_fontset_from_font_name (result);
+
+ /* Since x_new_font doesn't update any fontset information, do it now. */
+ FRAME_FONTSET (f) = fontset;
+
+ #ifdef HAVE_X_I18N
+ if (FRAME_XIC (f)
+ && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
+ xic_set_xfontset (f, SDATA (fontset_ascii (fontset)));
+ #endif
+
+ return fontset_name (fontset);
+ }
+
+
+ /***********************************************************************
+ X Input Methods
+ ***********************************************************************/
+
+ #ifdef HAVE_X_I18N
+
+ #ifdef HAVE_X11R6
+
+ /* XIM destroy callback function, which is called whenever the
+ connection to input method XIM dies. CLIENT_DATA contains a
+ pointer to the x_display_info structure corresponding to XIM. */
+
+ static void
+ xim_destroy_callback (xim, client_data, call_data)
+ XIM xim;
+ XPointer client_data;
+ XPointer call_data;
+ {
+ struct x_display_info *dpyinfo = (struct x_display_info *) client_data;
+ Lisp_Object frame, tail;
+
+ BLOCK_INPUT;
+
+ /* No need to call XDestroyIC.. */
+ FOR_EACH_FRAME (tail, frame)
+ {
+ struct frame *f = XFRAME (frame);
+ if (FRAME_X_DISPLAY_INFO (f) == dpyinfo)
+ {
+ FRAME_XIC (f) = NULL;
+ if (FRAME_XIC_FONTSET (f))
+ {
+ XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
+ FRAME_XIC_FONTSET (f) = NULL;
+ }
+ }
+ }
+
+ /* No need to call XCloseIM. */
+ dpyinfo->xim = NULL;
+ XFree (dpyinfo->xim_styles);
+ UNBLOCK_INPUT;
+ }
+
+ #endif /* HAVE_X11R6 */
+
+ #ifdef HAVE_X11R6
+ /* This isn't prototyped in OSF 5.0 or 5.1a. */
+ extern char *XSetIMValues P_ ((XIM, ...));
+ #endif
+
+ /* Open the connection to the XIM server on display DPYINFO.
+ RESOURCE_NAME is the resource name Emacs uses. */
+
+ static void
+ xim_open_dpy (dpyinfo, resource_name)
+ struct x_display_info *dpyinfo;
+ char *resource_name;
+ {
+ XIM xim;
+
+ #ifdef HAVE_XIM
+ if (use_xim)
+ {
+ xim = XOpenIM (dpyinfo->display, dpyinfo->xrdb, resource_name,
+ EMACS_CLASS);
+ dpyinfo->xim = xim;
+
+ if (xim)
+ {
+ #ifdef HAVE_X11R6
+ XIMCallback destroy;
+ #endif
+
+ /* Get supported styles and XIM values. */
+ XGetIMValues (xim, XNQueryInputStyle, &dpyinfo->xim_styles, NULL);
+
+ #ifdef HAVE_X11R6
+ destroy.callback = xim_destroy_callback;
+ destroy.client_data = (XPointer)dpyinfo;
+ XSetIMValues (xim, XNDestroyCallback, &destroy, NULL);
+ #endif
+ }
+ }
+
+ else
+ #endif /* HAVE_XIM */
+ dpyinfo->xim = NULL;
+ }
+
+
+ #ifdef HAVE_X11R6_XIM
+
+ struct xim_inst_t
+ {
+ struct x_display_info *dpyinfo;
+ char *resource_name;
+ };
+
+ /* XIM instantiate callback function, which is called whenever an XIM
+ server is available. DISPLAY is the display of the XIM.
+ CLIENT_DATA contains a pointer to an xim_inst_t structure created
+ when the callback was registered. */
+
+ static void
+ xim_instantiate_callback (display, client_data, call_data)
+ Display *display;
+ XPointer client_data;
+ XPointer call_data;
+ {
+ struct xim_inst_t *xim_inst = (struct xim_inst_t *) client_data;
+ struct x_display_info *dpyinfo = xim_inst->dpyinfo;
+
+ /* We don't support multiple XIM connections. */
+ if (dpyinfo->xim)
+ return;
+
+ xim_open_dpy (dpyinfo, xim_inst->resource_name);
+
+ /* Create XIC for the existing frames on the same display, as long
+ as they have no XIC. */
+ if (dpyinfo->xim && dpyinfo->reference_count > 0)
+ {
+ Lisp_Object tail, frame;
+
+ BLOCK_INPUT;
+ FOR_EACH_FRAME (tail, frame)
+ {
+ struct frame *f = XFRAME (frame);
+
+ if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo)
+ if (FRAME_XIC (f) == NULL)
+ {
+ create_frame_xic (f);
+ if (FRAME_XIC_STYLE (f) & XIMStatusArea)
+ xic_set_statusarea (f);
+ if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
+ {
+ struct window *w = XWINDOW (f->selected_window);
+ xic_set_preeditarea (w, w->cursor.x, w->cursor.y);
+ }
+ }
+ }
+
+ UNBLOCK_INPUT;
+ }
+ }
+
+ #endif /* HAVE_X11R6_XIM */
+
+
+ /* Open a connection to the XIM server on display DPYINFO.
+ RESOURCE_NAME is the resource name for Emacs. On X11R5, open the
+ connection only at the first time. On X11R6, open the connection
+ in the XIM instantiate callback function. */
+
+ static void
+ xim_initialize (dpyinfo, resource_name)
+ struct x_display_info *dpyinfo;
+ char *resource_name;
+ {
+ #ifdef HAVE_XIM
+ if (use_xim)
+ {
+ #ifdef HAVE_X11R6_XIM
+ struct xim_inst_t *xim_inst;
+ int len;
+
+ dpyinfo->xim = NULL;
+ xim_inst = (struct xim_inst_t *) xmalloc (sizeof (struct xim_inst_t));
+ xim_inst->dpyinfo = dpyinfo;
+ len = strlen (resource_name);
+ xim_inst->resource_name = (char *) xmalloc (len + 1);
+ bcopy (resource_name, xim_inst->resource_name, len + 1);
+ XRegisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
+ resource_name, EMACS_CLASS,
+ xim_instantiate_callback,
+ /* This is XPointer in XFree86
+ but (XPointer *) on Tru64, at
+ least, hence the configure test. */
+ (XRegisterIMInstantiateCallback_arg6)
xim_inst);
+ #else /* not HAVE_X11R6_XIM */
+ dpyinfo->xim = NULL;
+ xim_open_dpy (dpyinfo, resource_name);
+ #endif /* not HAVE_X11R6_XIM */
+
+ }
+ else
+ #endif /* HAVE_XIM */
+ dpyinfo->xim = NULL;
+ }
+
+
+ /* Close the connection to the XIM server on display DPYINFO. */
+
+ static void
+ xim_close_dpy (dpyinfo)
+ struct x_display_info *dpyinfo;
+ {
+ #ifdef HAVE_XIM
+ if (use_xim)
+ {
+ #ifdef HAVE_X11R6_XIM
+ if (dpyinfo->display)
+ XUnregisterIMInstantiateCallback (dpyinfo->display, dpyinfo->xrdb,
+ NULL, EMACS_CLASS,
+ xim_instantiate_callback, NULL);
+ #endif /* not HAVE_X11R6_XIM */
+ if (dpyinfo->display)
+ XCloseIM (dpyinfo->xim);
+ dpyinfo->xim = NULL;
+ XFree (dpyinfo->xim_styles);
+ }
+ #endif /* HAVE_XIM */
+ }
+
+ #endif /* not HAVE_X11R6_XIM */
+
+
+
+ /* Calculate the absolute position in frame F
+ from its current recorded position values and gravity. */
+
+ void
+ x_calc_absolute_position (f)
+ struct frame *f;
+ {
+ Window child;
+ int win_x = 0, win_y = 0;
+ int flags = f->size_hint_flags;
+ int this_window;
+
+ /* We have nothing to do if the current position
+ is already for the top-left corner. */
+ if (! ((flags & XNegative) || (flags & YNegative)))
+ return;
+
+ this_window = FRAME_OUTER_WINDOW (f);
+
+ /* Find the position of the outside upper-left corner of
+ the inner window, with respect to the outer window.
+ But do this only if we will need the results. */
+ if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
+ {
+ int count;
+
+ BLOCK_INPUT;
+ count = x_catch_errors (FRAME_X_DISPLAY (f));
+ while (1)
+ {
+ x_clear_errors (FRAME_X_DISPLAY (f));
+ XTranslateCoordinates (FRAME_X_DISPLAY (f),
+
+ /* From-window, to-window. */
+ this_window,
+ f->output_data.x->parent_desc,
+
+ /* From-position, to-position. */
+ 0, 0, &win_x, &win_y,
+
+ /* Child of win. */
+ &child);
+ if (x_had_errors_p (FRAME_X_DISPLAY (f)))
+ {
+ Window newroot, newparent = 0xdeadbeef;
+ Window *newchildren;
+ unsigned int nchildren;
+
+ if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
+ &newparent, &newchildren, &nchildren))
+ break;
+
+ XFree ((char *) newchildren);
+
+ f->output_data.x->parent_desc = newparent;
+ }
+ else
+ break;
+ }
+
+ x_uncatch_errors (FRAME_X_DISPLAY (f), count);
+ UNBLOCK_INPUT;
+ }
+
+ /* Treat negative positions as relative to the leftmost bottommost
+ position that fits on the screen. */
+ if (flags & XNegative)
+ f->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
+ - 2 * f->border_width - win_x
+ - FRAME_PIXEL_WIDTH (f)
+ + f->left_pos);
+
+ {
+ int height = FRAME_PIXEL_HEIGHT (f);
+
+ #if defined USE_X_TOOLKIT && defined USE_MOTIF
+ /* Something is fishy here. When using Motif, starting Emacs with
+ `-g -0-0', the frame appears too low by a few pixels.
+
+ This seems to be so because initially, while Emacs is starting,
+ the column widget's height and the frame's pixel height are
+ different. The column widget's height is the right one. In
+ later invocations, when Emacs is up, the frame's pixel height
+ is right, though.
+
+ It's not obvious where the initial small difference comes from.
+ 2000-12-01, gerd. */
+
+ XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
+ #endif
+
+ if (flags & YNegative)
+ f->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
+ - 2 * f->border_width
+ - win_y
+ - height
+ + f->top_pos);
+ }
+
+ /* The left_pos and top_pos
+ are now relative to the top and left screen edges,
+ so the flags should correspond. */
+ f->size_hint_flags &= ~ (XNegative | YNegative);
+ }
+
+ /* CHANGE_GRAVITY is 1 when calling from Fset_frame_position,
+ to really change the position, and 0 when calling from
+ x_make_frame_visible (in that case, XOFF and YOFF are the current
+ position values). It is -1 when calling from x_set_frame_parameters,
+ which means, do adjust for borders but don't change the gravity. */
+
+ void
+ x_set_offset (f, xoff, yoff, change_gravity)
+ struct frame *f;
+ register int xoff, yoff;
+ int change_gravity;
+ {
+ int modified_top, modified_left;
+
+ if (change_gravity > 0)
+ {
+ f->top_pos = yoff;
+ f->left_pos = xoff;
+ f->size_hint_flags &= ~ (XNegative | YNegative);
+ if (xoff < 0)
+ f->size_hint_flags |= XNegative;
+ if (yoff < 0)
+ f->size_hint_flags |= YNegative;
+ f->win_gravity = NorthWestGravity;
+ }
+ x_calc_absolute_position (f);
+
+ BLOCK_INPUT;
+ x_wm_set_size_hint (f, (long) 0, 0);
+
+ modified_left = f->left_pos;
+ modified_top = f->top_pos;
+ #if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
+ this seems to be unnecessary and incorrect. rms, 4/17/97. */
+ /* It is a mystery why we need to add the border_width here
+ when the frame is already visible, but experiment says we do. */
+ if (change_gravity != 0)
+ {
+ modified_left += f->border_width;
+ modified_top += f->border_width;
+ }
+ #endif
+
+ XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+ modified_left, modified_top);
+ UNBLOCK_INPUT;
+ }
+
+ /* Check if we need to resize the frame due to a fullscreen request.
+ If so needed, resize the frame. */
+ static void
+ x_check_fullscreen (f)
+ struct frame *f;
+ {
+ if (f->want_fullscreen & FULLSCREEN_BOTH)
+ {
+ int width, height, ign;
+
+ x_real_positions (f, &f->left_pos, &f->top_pos);
+
+ x_fullscreen_adjust (f, &width, &height, &ign, &ign);
+
+ /* We do not need to move the window, it shall be taken care of
+ when setting WM manager hints.
+ If the frame is visible already, the position is checked by
+ x_check_fullscreen_move. */
+ if (FRAME_COLS (f) != width || FRAME_LINES (f) != height)
+ {
+ change_frame_size (f, height, width, 0, 1, 0);
+ SET_FRAME_GARBAGED (f);
+ cancel_mouse_face (f);
+
+ /* Wait for the change of frame size to occur */
+ f->want_fullscreen |= FULLSCREEN_WAIT;
+ }
+ }
+ }
+
+ /* If frame parameters are set after the frame is mapped, we need to move
+ the window. This is done in xfns.c.
+ Some window managers moves the window to the right position, some
+ moves the outer window manager window to the specified position.
+ Here we check that we are in the right spot. If not, make a second
+ move, assuming we are dealing with the second kind of window manager. */
+ static void
+ x_check_fullscreen_move (f)
+ struct frame *f;
+ {
+ if (f->want_fullscreen & FULLSCREEN_MOVE_WAIT)
+ {
+ int expect_top = f->top_pos;
+ int expect_left = f->left_pos;
+
+ if (f->want_fullscreen & FULLSCREEN_HEIGHT)
+ expect_top = 0;
+ if (f->want_fullscreen & FULLSCREEN_WIDTH)
+ expect_left = 0;
+
+ if (expect_top != f->top_pos || expect_left != f->left_pos)
+ x_set_offset (f, expect_left, expect_top, 1);
+
+ /* Just do this once */
+ f->want_fullscreen &= ~FULLSCREEN_MOVE_WAIT;
+ }
+ }
+
+
+ /* Change the size of frame F's X window to COLS/ROWS in the case F
+ doesn't have a widget. If CHANGE_GRAVITY is 1, we change to
+ top-left-corner window gravity for this size change and subsequent
+ size changes. Otherwise we leave the window gravity unchanged. */
+
+ static void
+ x_set_window_size_1 (f, change_gravity, cols, rows)
+ struct frame *f;
+ int change_gravity;
+ int cols, rows;
+ {
+ int pixelwidth, pixelheight;
+
+ check_frame_size (f, &rows, &cols);
+ f->scroll_bar_actual_width
+ = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
+ ? 0
+ : FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0
+ ? FRAME_CONFIG_SCROLL_BAR_WIDTH (f)
+ : (FRAME_CONFIG_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)));
+
+ compute_fringe_widths (f, 0);
+
+ pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, cols);
+ pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
+
+ f->win_gravity = NorthWestGravity;
+ x_wm_set_size_hint (f, (long) 0, 0);
+
+ XSync (FRAME_X_DISPLAY (f), False);
+ XResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ pixelwidth, pixelheight);
+
+ /* Now, strictly speaking, we can't be sure that this is accurate,
+ but the window manager will get around to dealing with the size
+ change request eventually, and we'll hear how it went when the
+ ConfigureNotify event gets here.
+
+ We could just not bother storing any of this information here,
+ and let the ConfigureNotify event set everything up, but that
+ might be kind of confusing to the Lisp code, since size changes
+ wouldn't be reported in the frame parameters until some random
+ point in the future when the ConfigureNotify event arrives.
+
+ We pass 1 for DELAY since we can't run Lisp code inside of
+ a BLOCK_INPUT. */
+ change_frame_size (f, rows, cols, 0, 1, 0);
+ FRAME_PIXEL_WIDTH (f) = pixelwidth;
+ FRAME_PIXEL_HEIGHT (f) = pixelheight;
+
+ /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
+ receive in the ConfigureNotify event; if we get what we asked
+ for, then the event won't cause the screen to become garbaged, so
+ we have to make sure to do it here. */
+ SET_FRAME_GARBAGED (f);
+
+ XFlush (FRAME_X_DISPLAY (f));
+ }
+
+
+ /* Call this to change the size of frame F's x-window.
+ If CHANGE_GRAVITY is 1, we change to top-left-corner window gravity
+ for this size change and subsequent size changes.
+ Otherwise we leave the window gravity unchanged. */
+
+ void
+ x_set_window_size (f, change_gravity, cols, rows)
+ struct frame *f;
+ int change_gravity;
+ int cols, rows;
+ {
+ BLOCK_INPUT;
+
+ #ifdef USE_GTK
+ if (FRAME_GTK_WIDGET (f))
+ xg_frame_set_char_size (f, cols, rows);
+ else
+ x_set_window_size_1 (f, change_gravity, cols, rows);
+ #elif USE_X_TOOLKIT
+
+ if (f->output_data.x->widget != NULL)
+ {
+ /* The x and y position of the widget is clobbered by the
+ call to XtSetValues within EmacsFrameSetCharSize.
+ This is a real kludge, but I don't understand Xt so I can't
+ figure out a correct fix. Can anyone else tell me? -- rms. */
+ int xpos = f->output_data.x->widget->core.x;
+ int ypos = f->output_data.x->widget->core.y;
+ EmacsFrameSetCharSize (f->output_data.x->edit_widget, cols, rows);
+ f->output_data.x->widget->core.x = xpos;
+ f->output_data.x->widget->core.y = ypos;
+ }
+ else
+ x_set_window_size_1 (f, change_gravity, cols, rows);
+
+ #else /* not USE_X_TOOLKIT */
+
+ x_set_window_size_1 (f, change_gravity, cols, rows);
+
+ #endif /* not USE_X_TOOLKIT */
+
+ /* If cursor was outside the new size, mark it as off. */
+ mark_window_cursors_off (XWINDOW (f->root_window));
+
+ /* Clear out any recollection of where the mouse highlighting was,
+ since it might be in a place that's outside the new frame size.
+ Actually checking whether it is outside is a pain in the neck,
+ so don't try--just let the highlighting be done afresh with new size. */
+ cancel_mouse_face (f);
+
+ UNBLOCK_INPUT;
+ }
+
+ /* Mouse warping. */
+
+ void
+ x_set_mouse_position (f, x, y)
+ struct frame *f;
+ int x, y;
+ {
+ int pix_x, pix_y;
+
+ pix_x = FRAME_COL_TO_PIXEL_X (f, x) + FRAME_COLUMN_WIDTH (f) / 2;
+ pix_y = FRAME_LINE_TO_PIXEL_Y (f, y) + FRAME_LINE_HEIGHT (f) / 2;
+
+ if (pix_x < 0) pix_x = 0;
+ if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
+
+ if (pix_y < 0) pix_y = 0;
+ if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
+
+ BLOCK_INPUT;
+
+ XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
+ 0, 0, 0, 0, pix_x, pix_y);
+ UNBLOCK_INPUT;
+ }
+
+ /* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */
+
+ void
+ x_set_mouse_pixel_position (f, pix_x, pix_y)
+ struct frame *f;
+ int pix_x, pix_y;
+ {
+ BLOCK_INPUT;
+
+ XWarpPointer (FRAME_X_DISPLAY (f), None, FRAME_X_WINDOW (f),
+ 0, 0, 0, 0, pix_x, pix_y);
+ UNBLOCK_INPUT;
+ }
+
+ /* focus shifting, raising and lowering. */
+
+ void
+ x_focus_on_frame (f)
+ struct frame *f;
+ {
+ #if 0 /* This proves to be unpleasant. */
+ x_raise_frame (f);
+ #endif
+ #if 0
+ /* I don't think that the ICCCM allows programs to do things like this
+ without the interaction of the window manager. Whatever you end up
+ doing with this code, do it to x_unfocus_frame too. */
+ XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ RevertToPointerRoot, CurrentTime);
+ #endif /* ! 0 */
+ }
+
+ void
+ x_unfocus_frame (f)
+ struct frame *f;
+ {
+ #if 0
+ /* Look at the remarks in x_focus_on_frame. */
+ if (FRAME_X_DISPLAY_INFO (f)->x_focus_frame == f)
+ XSetInputFocus (FRAME_X_DISPLAY (f), PointerRoot,
+ RevertToPointerRoot, CurrentTime);
+ #endif /* ! 0 */
+ }
+
+ /* Raise frame F. */
+
+ void
+ x_raise_frame (f)
+ struct frame *f;
+ {
+ if (f->async_visible)
+ {
+ BLOCK_INPUT;
+ XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
+ XFlush (FRAME_X_DISPLAY (f));
+ UNBLOCK_INPUT;
+ }
+ }
+
+ /* Lower frame F. */
+
+ void
+ x_lower_frame (f)
+ struct frame *f;
+ {
+ if (f->async_visible)
+ {
+ BLOCK_INPUT;
+ XLowerWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
+ XFlush (FRAME_X_DISPLAY (f));
+ UNBLOCK_INPUT;
+ }
+ }
+
+ static void
+ XTframe_raise_lower (f, raise_flag)
+ FRAME_PTR f;
+ int raise_flag;
+ {
+ if (raise_flag)
+ x_raise_frame (f);
+ else
+ x_lower_frame (f);
+ }
+
+ /* Change of visibility. */
+
+ /* This tries to wait until the frame is really visible.
+ However, if the window manager asks the user where to position
+ the frame, this will return before the user finishes doing that.
+ The frame will not actually be visible at that time,
+ but it will become visible later when the window manager
+ finishes with it. */
+
+ void
+ x_make_frame_visible (f)
+ struct frame *f;
+ {
+ Lisp_Object type;
+ int original_top, original_left;
+ int retry_count = 2;
+
+ retry:
+
+ BLOCK_INPUT;
+
+ type = x_icon_type (f);
+ if (!NILP (type))
+ x_bitmap_icon (f, type);
+
+ if (! FRAME_VISIBLE_P (f))
+ {
+ /* We test FRAME_GARBAGED_P here to make sure we don't
+ call x_set_offset a second time
+ if we get to x_make_frame_visible a second time
+ before the window gets really visible. */
+ if (! FRAME_ICONIFIED_P (f)
+ && ! f->output_data.x->asked_for_visible)
+ x_set_offset (f, f->left_pos, f->top_pos, 0);
+
+ f->output_data.x->asked_for_visible = 1;
+
+ if (! EQ (Vx_no_window_manager, Qt))
+ x_wm_set_window_state (f, NormalState);
+ #ifdef USE_X_TOOLKIT
+ /* This was XtPopup, but that did nothing for an iconified frame. */
+ XtMapWidget (f->output_data.x->widget);
+ #else /* not USE_X_TOOLKIT */
+ #ifdef USE_GTK
+ gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
+ gtk_window_deiconify (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
+ #else
+ XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
+ #endif /* not USE_GTK */
+ #endif /* not USE_X_TOOLKIT */
+ #if 0 /* This seems to bring back scroll bars in the wrong places
+ if the window configuration has changed. They seem
+ to come back ok without this. */
+ if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+ XMapSubwindows (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
+ #endif
+ }
+
+ XFlush (FRAME_X_DISPLAY (f));
+
+ /* Synchronize to ensure Emacs knows the frame is visible
+ before we do anything else. We do this loop with input not blocked
+ so that incoming events are handled. */
+ {
+ Lisp_Object frame;
+ int count;
+ /* This must be before UNBLOCK_INPUT
+ since events that arrive in response to the actions above
+ will set it when they are handled. */
+ int previously_visible = f->output_data.x->has_been_visible;
+
+ original_left = f->left_pos;
+ original_top = f->top_pos;
+
+ /* This must come after we set COUNT. */
+ UNBLOCK_INPUT;
+
+ /* We unblock here so that arriving X events are processed. */
+
+ /* Now move the window back to where it was "supposed to be".
+ But don't do it if the gravity is negative.
+ When the gravity is negative, this uses a position
+ that is 3 pixels too low. Perhaps that's really the border width.
+
+ Don't do this if the window has never been visible before,
+ because the window manager may choose the position
+ and we don't want to override it. */
+
+ if (! FRAME_VISIBLE_P (f) && ! FRAME_ICONIFIED_P (f)
+ && f->win_gravity == NorthWestGravity
+ && previously_visible)
+ {
+ Drawable rootw;
+ int x, y;
+ unsigned int width, height, border, depth;
+
+ BLOCK_INPUT;
+
+ /* On some window managers (such as FVWM) moving an existing
+ window, even to the same place, causes the window manager
+ to introduce an offset. This can cause the window to move
+ to an unexpected location. Check the geometry (a little
+ slow here) and then verify that the window is in the right
+ place. If the window is not in the right place, move it
+ there, and take the potential window manager hit. */
+ XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+ &rootw, &x, &y, &width, &height, &border, &depth);
+
+ if (original_left != x || original_top != y)
+ XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+ original_left, original_top);
+
+ UNBLOCK_INPUT;
+ }
+
+ XSETFRAME (frame, f);
+
+ /* Wait until the frame is visible. Process X events until a
+ MapNotify event has been seen, or until we think we won't get a
+ MapNotify at all.. */
+ for (count = input_signal_count + 10;
+ input_signal_count < count && !FRAME_VISIBLE_P (f);)
+ {
+ /* Force processing of queued events. */
+ x_sync (f);
+
+ /* Machines that do polling rather than SIGIO have been
+ observed to go into a busy-wait here. So we'll fake an
+ alarm signal to let the handler know that there's something
+ to be read. We used to raise a real alarm, but it seems
+ that the handler isn't always enabled here. This is
+ probably a bug. */
+ if (input_polling_used ())
+ {
+ /* It could be confusing if a real alarm arrives while
+ processing the fake one. Turn it off and let the
+ handler reset it. */
+ extern void poll_for_input_1 P_ ((void));
+ int old_poll_suppress_count = poll_suppress_count;
+ poll_suppress_count = 1;
+ poll_for_input_1 ();
+ poll_suppress_count = old_poll_suppress_count;
+ }
+
+ /* See if a MapNotify event has been processed. */
+ FRAME_SAMPLE_VISIBILITY (f);
+ }
+
+ /* 2000-09-28: In
+
+ (let ((f (selected-frame)))
+ (iconify-frame f)
+ (raise-frame f))
+
+ the frame is not raised with various window managers on
+ FreeBSD, GNU/Linux and Solaris. It turns out that, for some
+ unknown reason, the call to XtMapWidget is completely ignored.
+ Mapping the widget a second time works. */
+
+ if (!FRAME_VISIBLE_P (f) && --retry_count > 0)
+ goto retry;
+ }
+ }
+
+ /* Change from mapped state to withdrawn state. */
+
+ /* Make the frame visible (mapped and not iconified). */
+
+ void
+ x_make_frame_invisible (f)
+ struct frame *f;
+ {
+ Window window;
+
+ /* Use the frame's outermost window, not the one we normally draw on. */
+ window = FRAME_OUTER_WINDOW (f);
+
+ /* Don't keep the highlight on an invisible frame. */
+ if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
+ FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
+
+ #if 0/* This might add unreliability; I don't trust it -- rms. */
+ if (! f->async_visible && ! f->async_iconified)
+ return;
+ #endif
+
+ BLOCK_INPUT;
+
+ /* Before unmapping the window, update the WM_SIZE_HINTS property to claim
+ that the current position of the window is user-specified, rather than
+ program-specified, so that when the window is mapped again, it will be
+ placed at the same location, without forcing the user to position it
+ by hand again (they have already done that once for this window.) */
+ x_wm_set_size_hint (f, (long) 0, 1);
+
+ #ifdef USE_GTK
+ if (FRAME_GTK_OUTER_WIDGET (f))
+ gtk_widget_hide (FRAME_GTK_OUTER_WIDGET (f));
+ else
+ #endif
+ {
+ #ifdef HAVE_X11R4
+
+ if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
+ DefaultScreen (FRAME_X_DISPLAY (f))))
+ {
+ UNBLOCK_INPUT_RESIGNAL;
+ error ("Can't notify window manager of window withdrawal");
+ }
+ #else /* ! defined (HAVE_X11R4) */
+
+ /* Tell the window manager what we're going to do. */
+ if (! EQ (Vx_no_window_manager, Qt))
+ {
+ XEvent unmap;
+
+ unmap.xunmap.type = UnmapNotify;
+ unmap.xunmap.window = window;
+ unmap.xunmap.event = DefaultRootWindow (FRAME_X_DISPLAY (f));
+ unmap.xunmap.from_configure = False;
+ if (! XSendEvent (FRAME_X_DISPLAY (f),
+ DefaultRootWindow (FRAME_X_DISPLAY (f)),
+ False,
+ SubstructureRedirectMaskSubstructureNotifyMask,
+ &unmap))
+ {
+ UNBLOCK_INPUT_RESIGNAL;
+ error ("Can't notify window manager of withdrawal");
+ }
+ }
+
+ /* Unmap the window ourselves. Cheeky! */
+ XUnmapWindow (FRAME_X_DISPLAY (f), window);
+ #endif /* ! defined (HAVE_X11R4) */
+ }
+
+ /* We can't distinguish this from iconification
+ just by the event that we get from the server.
+ So we can't win using the usual strategy of letting
+ FRAME_SAMPLE_VISIBILITY set this. So do it by hand,
+ and synchronize with the server to make sure we agree. */
+ f->visible = 0;
+ FRAME_ICONIFIED_P (f) = 0;
+ f->async_visible = 0;
+ f->async_iconified = 0;
+
+ x_sync (f);
+
+ UNBLOCK_INPUT;
+ }
+
+ /* Change window state from mapped to iconified. */
+
+ void
+ x_iconify_frame (f)
+ struct frame *f;
+ {
+ int result;
+ Lisp_Object type;
+
+ /* Don't keep the highlight on an invisible frame. */
+ if (FRAME_X_DISPLAY_INFO (f)->x_highlight_frame == f)
+ FRAME_X_DISPLAY_INFO (f)->x_highlight_frame = 0;
+
+ if (f->async_iconified)
+ return;
+
+ BLOCK_INPUT;
+
+ FRAME_SAMPLE_VISIBILITY (f);
+
+ type = x_icon_type (f);
+ if (!NILP (type))
+ x_bitmap_icon (f, type);
+
+ #ifdef USE_GTK
+ if (FRAME_GTK_OUTER_WIDGET (f))
+ {
+ if (! FRAME_VISIBLE_P (f))
+ gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
+
+ gtk_window_iconify (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
+ f->iconified = 1;
+ f->visible = 1;
+ f->async_iconified = 1;
+ f->async_visible = 0;
+ UNBLOCK_INPUT;
+ return;
+ }
+ #endif
+
+ #ifdef USE_X_TOOLKIT
+
+ if (! FRAME_VISIBLE_P (f))
+ {
+ if (! EQ (Vx_no_window_manager, Qt))
+ x_wm_set_window_state (f, IconicState);
+ /* This was XtPopup, but that did nothing for an iconified frame. */
+ XtMapWidget (f->output_data.x->widget);
+ /* The server won't give us any event to indicate
+ that an invisible frame was changed to an icon,
+ so we have to record it here. */
+ f->iconified = 1;
+ f->visible = 1;
+ f->async_iconified = 1;
+ f->async_visible = 0;
+ UNBLOCK_INPUT;
+ return;
+ }
+
+ result = XIconifyWindow (FRAME_X_DISPLAY (f),
+ XtWindow (f->output_data.x->widget),
+ DefaultScreen (FRAME_X_DISPLAY (f)));
+ UNBLOCK_INPUT;
+
+ if (!result)
+ error ("Can't notify window manager of iconification");
+
+ f->async_iconified = 1;
+ f->async_visible = 0;
+
+
+ BLOCK_INPUT;
+ XFlush (FRAME_X_DISPLAY (f));
+ UNBLOCK_INPUT;
+ #else /* not USE_X_TOOLKIT */
+
+ /* Make sure the X server knows where the window should be positioned,
+ in case the user deiconifies with the window manager. */
+ if (! FRAME_VISIBLE_P (f) && !FRAME_ICONIFIED_P (f))
+ x_set_offset (f, f->left_pos, f->top_pos, 0);
+
+ /* Since we don't know which revision of X we're running, we'll use both
+ the X11R3 and X11R4 techniques. I don't know if this is a good idea. */
+
+ /* X11R4: send a ClientMessage to the window manager using the
+ WM_CHANGE_STATE type. */
+ {
+ XEvent message;
+
+ message.xclient.window = FRAME_X_WINDOW (f);
+ message.xclient.type = ClientMessage;
+ message.xclient.message_type = FRAME_X_DISPLAY_INFO
(f)->Xatom_wm_change_state;
+ message.xclient.format = 32;
+ message.xclient.data.l[0] = IconicState;
+
+ if (! XSendEvent (FRAME_X_DISPLAY (f),
+ DefaultRootWindow (FRAME_X_DISPLAY (f)),
+ False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &message))
+ {
+ UNBLOCK_INPUT_RESIGNAL;
+ error ("Can't notify window manager of iconification");
+ }
+ }
+
+ /* X11R3: set the initial_state field of the window manager hints to
+ IconicState. */
+ x_wm_set_window_state (f, IconicState);
+
+ if (!FRAME_VISIBLE_P (f))
+ {
+ /* If the frame was withdrawn, before, we must map it. */
+ XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
+ }
+
+ f->async_iconified = 1;
+ f->async_visible = 0;
+
+ XFlush (FRAME_X_DISPLAY (f));
+ UNBLOCK_INPUT;
+ #endif /* not USE_X_TOOLKIT */
+ }
+
+
+ /* Free X resources of frame F. */
+
+ void
+ x_free_frame_resources (f)
+ struct frame *f;
+ {
+ struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ Lisp_Object bar;
+ struct scroll_bar *b;
+
+ BLOCK_INPUT;
+
+ /* If a display connection is dead, don't try sending more
+ commands to the X server. */
+ if (dpyinfo->display)
+ {
+ if (f->output_data.x->icon_desc)
+ XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
+
+ #ifdef USE_X_TOOLKIT
+ /* Explicitly destroy the scroll bars of the frame. Without
+ this, we get "BadDrawable" errors from the toolkit later on,
+ presumably from expose events generated for the disappearing
+ toolkit scroll bars. */
+ for (bar = FRAME_SCROLL_BARS (f); !NILP (bar); bar = b->next)
+ {
+ b = XSCROLL_BAR (bar);
+ x_scroll_bar_remove (b);
+ }
+ #endif
+
+ #ifdef HAVE_X_I18N
+ if (FRAME_XIC (f))
+ free_frame_xic (f);
+ #endif
+
+ #ifdef USE_X_TOOLKIT
+ if (f->output_data.x->widget)
+ {
+ XtDestroyWidget (f->output_data.x->widget);
+ f->output_data.x->widget = NULL;
+ }
+ /* Tooltips don't have widgets, only a simple X window, even if
+ we are using a toolkit. */
+ else if (FRAME_X_WINDOW (f))
+ XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
+
+ free_frame_menubar (f);
+ #else /* !USE_X_TOOLKIT */
+
+ #ifdef USE_GTK
+ /* In the GTK version, tooltips are normal X
+ frames. We must check and free both types. */
+ if (FRAME_GTK_OUTER_WIDGET (f))
+ {
+ gtk_widget_destroy (FRAME_GTK_OUTER_WIDGET (f));
+ FRAME_X_WINDOW (f) = 0; /* Set to avoid XDestroyWindow below */
+ FRAME_GTK_OUTER_WIDGET (f) = 0;
+ }
+ #endif /* USE_GTK */
+
+ if (FRAME_X_WINDOW (f))
+ XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
+ #endif /* !USE_X_TOOLKIT */
+
+ unload_color (f, f->output_data.x->foreground_pixel);
+ unload_color (f, f->output_data.x->background_pixel);
+ unload_color (f, f->output_data.x->cursor_pixel);
+ unload_color (f, f->output_data.x->cursor_foreground_pixel);
+ unload_color (f, f->output_data.x->border_pixel);
+ unload_color (f, f->output_data.x->mouse_pixel);
+
+ if (f->output_data.x->scroll_bar_background_pixel != -1)
+ unload_color (f, f->output_data.x->scroll_bar_background_pixel);
+ if (f->output_data.x->scroll_bar_foreground_pixel != -1)
+ unload_color (f, f->output_data.x->scroll_bar_foreground_pixel);
+ #ifdef USE_TOOLKIT_SCROLL_BARS
+ /* Scrollbar shadow colors. */
+ if (f->output_data.x->scroll_bar_top_shadow_pixel != -1)
+ unload_color (f, f->output_data.x->scroll_bar_top_shadow_pixel);
+ if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1)
+ unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel);
+ #endif /* USE_TOOLKIT_SCROLL_BARS */
+ if (f->output_data.x->white_relief.allocated_p)
+ unload_color (f, f->output_data.x->white_relief.pixel);
+ if (f->output_data.x->black_relief.allocated_p)
+ unload_color (f, f->output_data.x->black_relief.pixel);
+
+ if (FRAME_FACE_CACHE (f))
+ free_frame_faces (f);
+
+ x_free_gcs (f);
+ XFlush (FRAME_X_DISPLAY (f));
+ }
+
+ if (f->output_data.x->saved_menu_event)
+ xfree (f->output_data.x->saved_menu_event);
+
+ xfree (f->output_data.x);
+ f->output_data.x = NULL;
+
+ if (f == dpyinfo->x_focus_frame)
+ dpyinfo->x_focus_frame = 0;
+ if (f == dpyinfo->x_focus_event_frame)
+ dpyinfo->x_focus_event_frame = 0;
+ if (f == dpyinfo->x_highlight_frame)
+ dpyinfo->x_highlight_frame = 0;
+
+ if (f == dpyinfo->mouse_face_mouse_frame)
+ {
+ dpyinfo->mouse_face_beg_row
+ = dpyinfo->mouse_face_beg_col = -1;
+ dpyinfo->mouse_face_end_row
+ = dpyinfo->mouse_face_end_col = -1;
+ dpyinfo->mouse_face_window = Qnil;
+ dpyinfo->mouse_face_deferred_gc = 0;
+ dpyinfo->mouse_face_mouse_frame = 0;
+ }
+
+ UNBLOCK_INPUT;
+ }
+
+
+ /* Destroy the X window of frame F. */
+
+ void
+ x_destroy_window (f)
+ struct frame *f;
+ {
+ struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+
+ /* If a display connection is dead, don't try sending more
+ commands to the X server. */
+ if (dpyinfo->display != 0)
+ x_free_frame_resources (f);
+
+ dpyinfo->reference_count--;
+ }
+
+
+ /* Setting window manager hints. */
+
+ /* Set the normal size hints for the window manager, for frame F.
+ FLAGS is the flags word to use--or 0 meaning preserve the flags
+ that the window now has.
+ If USER_POSITION is nonzero, we set the USPosition
+ flag (this is useful when FLAGS is 0).
+ The GTK version is in gtkutils.c */
+
+ #ifndef USE_GTK
+ void
+ x_wm_set_size_hint (f, flags, user_position)
+ struct frame *f;
+ long flags;
+ int user_position;
+ {
+ XSizeHints size_hints;
+
+ #ifdef USE_X_TOOLKIT
+ Arg al[2];
+ int ac = 0;
+ Dimension widget_width, widget_height;
+ #endif
+
+ Window window = FRAME_OUTER_WINDOW (f);
+
+ /* Setting PMaxSize caused various problems. */
+ size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
+
+ size_hints.x = f->left_pos;
+ size_hints.y = f->top_pos;
+
+ #ifdef USE_X_TOOLKIT
+ XtSetArg (al[ac], XtNwidth, &widget_width); ac++;
+ XtSetArg (al[ac], XtNheight, &widget_height); ac++;
+ XtGetValues (f->output_data.x->widget, al, ac);
+ size_hints.height = widget_height;
+ size_hints.width = widget_width;
+ #else /* not USE_X_TOOLKIT */
+ size_hints.height = FRAME_PIXEL_HEIGHT (f);
+ size_hints.width = FRAME_PIXEL_WIDTH (f);
+ #endif /* not USE_X_TOOLKIT */
+
+ size_hints.width_inc = FRAME_COLUMN_WIDTH (f);
+ size_hints.height_inc = FRAME_LINE_HEIGHT (f);
+ size_hints.max_width
+ = FRAME_X_DISPLAY_INFO (f)->width - FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
+ size_hints.max_height
+ = FRAME_X_DISPLAY_INFO (f)->height - FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f,
0);
+
+ /* Calculate the base and minimum sizes.
+
+ (When we use the X toolkit, we don't do it here.
+ Instead we copy the values that the widgets are using, below.) */
+ #ifndef USE_X_TOOLKIT
+ {
+ int base_width, base_height;
+ int min_rows = 0, min_cols = 0;
+
+ base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
+ base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
+
+ check_frame_size (f, &min_rows, &min_cols);
+
+ /* The window manager uses the base width hints to calculate the
+ current number of rows and columns in the frame while
+ resizing; min_width and min_height aren't useful for this
+ purpose, since they might not give the dimensions for a
+ zero-row, zero-column frame.
+
+ We use the base_width and base_height members if we have
+ them; otherwise, we set the min_width and min_height members
+ to the size for a zero x zero frame. */
+
+ #ifdef HAVE_X11R4
+ size_hints.flags |= PBaseSize;
+ size_hints.base_width = base_width;
+ size_hints.base_height = base_height;
+ size_hints.min_width = base_width + min_cols * size_hints.width_inc;
+ size_hints.min_height = base_height + min_rows * size_hints.height_inc;
+ #else
+ size_hints.min_width = base_width;
+ size_hints.min_height = base_height;
+ #endif
+ }
+
+ /* If we don't need the old flags, we don't need the old hint at all. */
+ if (flags)
+ {
+ size_hints.flags |= flags;
+ goto no_read;
+ }
+ #endif /* not USE_X_TOOLKIT */
+
+ {
+ XSizeHints hints; /* Sometimes I hate X Windows... */
+ long supplied_return;
+ int value;
+
+ #ifdef HAVE_X11R4
+ value = XGetWMNormalHints (FRAME_X_DISPLAY (f), window, &hints,
+ &supplied_return);
+ #else
+ value = XGetNormalHints (FRAME_X_DISPLAY (f), window, &hints);
+ #endif
+
+ #ifdef USE_X_TOOLKIT
+ size_hints.base_height = hints.base_height;
+ size_hints.base_width = hints.base_width;
+ size_hints.min_height = hints.min_height;
+ size_hints.min_width = hints.min_width;
+ #endif
+
+ if (flags)
+ size_hints.flags |= flags;
+ else
+ {
+ if (value == 0)
+ hints.flags = 0;
+ 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;
+ }
+ }
+
+ #ifndef USE_X_TOOLKIT
+ no_read:
+ #endif
+
+ #ifdef PWinGravity
+ size_hints.win_gravity = f->win_gravity;
+ size_hints.flags |= PWinGravity;
+
+ if (user_position)
+ {
+ size_hints.flags &= ~ PPosition;
+ size_hints.flags |= USPosition;
+ }
+ #endif /* PWinGravity */
+
+ #ifdef HAVE_X11R4
+ XSetWMNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
+ #else
+ XSetNormalHints (FRAME_X_DISPLAY (f), window, &size_hints);
+ #endif
+ }
+ #endif /* not USE_GTK */
+
+ /* Used for IconicState or NormalState */
+
+ void
+ x_wm_set_window_state (f, state)
+ struct frame *f;
+ int state;
+ {
+ #ifdef USE_X_TOOLKIT
+ Arg al[1];
+
+ XtSetArg (al[0], XtNinitialState, state);
+ XtSetValues (f->output_data.x->widget, al, 1);
+ #else /* not USE_X_TOOLKIT */
+ Window window = FRAME_X_WINDOW (f);
+
+ f->output_data.x->wm_hints.flags |= StateHint;
+ f->output_data.x->wm_hints.initial_state = state;
+
+ XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
+ #endif /* not USE_X_TOOLKIT */
+ }
+
+ void
+ x_wm_set_icon_pixmap (f, pixmap_id)
+ struct frame *f;
+ int pixmap_id;
+ {
+ Pixmap icon_pixmap, icon_mask;
+
+ #ifndef USE_X_TOOLKIT
+ Window window = FRAME_OUTER_WINDOW (f);
+ #endif
+
+ if (pixmap_id > 0)
+ {
+ icon_pixmap = x_bitmap_pixmap (f, pixmap_id);
+ f->output_data.x->wm_hints.icon_pixmap = icon_pixmap;
+ icon_mask = x_bitmap_mask (f, pixmap_id);
+ f->output_data.x->wm_hints.icon_mask = icon_mask;
+ }
+ else
+ {
+ /* It seems there is no way to turn off use of an icon pixmap.
+ The following line does it, only if no icon has yet been created,
+ for some window managers. But with mwm it crashes.
+ Some people say it should clear the IconPixmapHint bit in this case,
+ but that doesn't work, and the X consortium said it isn't the
+ right thing at all. Since there is no way to win,
+ best to explicitly give up. */
+ #if 0
+ f->output_data.x->wm_hints.icon_pixmap = None;
+ f->output_data.x->wm_hints.icon_mask = None;
+ #else
+ return;
+ #endif
+ }
+
+ #ifdef USE_X_TOOLKIT /* same as in x_wm_set_window_state. */
+
+ {
+ Arg al[1];
+ XtSetArg (al[0], XtNiconPixmap, icon_pixmap);
+ XtSetValues (f->output_data.x->widget, al, 1);
+ XtSetArg (al[0], XtNiconMask, icon_mask);
+ XtSetValues (f->output_data.x->widget, al, 1);
+ }
+
+ #else /* not USE_X_TOOLKIT */
+
+ f->output_data.x->wm_hints.flags |= (IconPixmapHint | IconMaskHint);
+ XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
+
+ #endif /* not USE_X_TOOLKIT */
+ }
+
+ void
+ x_wm_set_icon_position (f, icon_x, icon_y)
+ struct frame *f;
+ int icon_x, icon_y;
+ {
+ Window window = FRAME_OUTER_WINDOW (f);
+
+ f->output_data.x->wm_hints.flags |= IconPositionHint;
+ f->output_data.x->wm_hints.icon_x = icon_x;
+ f->output_data.x->wm_hints.icon_y = icon_y;
+
+ XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
+ }
+
+
+ /***********************************************************************
+ Fonts
+ ***********************************************************************/
+
+ /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
+
+ struct font_info *
+ x_get_font_info (f, font_idx)
+ FRAME_PTR f;
+ int font_idx;
+ {
+ return (FRAME_X_FONT_TABLE (f) + font_idx);
+ }
+
+
+ /* Return a list of names of available fonts matching PATTERN on frame F.
+
+ If SIZE is > 0, it is the size (maximum bounds width) of fonts
+ to be listed.
+
+ SIZE < 0 means include scalable fonts.
+
+ Frame F null means we have not yet created any frame on X, and
+ consult the first display in x_display_list. MAXNAMES sets a limit
+ on how many fonts to match. */
+
+ Lisp_Object
+ x_list_fonts (f, pattern, size, maxnames)
+ struct frame *f;
+ Lisp_Object pattern;
+ int size;
+ int maxnames;
+ {
+ Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
+ Lisp_Object tem, second_best;
+ struct x_display_info *dpyinfo
+ = f ? FRAME_X_DISPLAY_INFO (f) : x_display_list;
+ Display *dpy = dpyinfo->display;
+ int try_XLoadQueryFont = 0;
+ int count;
+ int allow_scalable_fonts_p = 0;
+
+ if (size < 0)
+ {
+ allow_scalable_fonts_p = 1;
+ size = 0;
+ }
+
+ patterns = Fassoc (pattern, Valternate_fontname_alist);
+ if (NILP (patterns))
+ patterns = Fcons (pattern, Qnil);
+
+ if (maxnames == 1 && !size)
+ /* We can return any single font matching PATTERN. */
+ try_XLoadQueryFont = 1;
+
+ for (; CONSP (patterns); patterns = XCDR (patterns))
+ {
+ int num_fonts;
+ char **names = NULL;
+
+ pattern = XCAR (patterns);
+ /* See if we cached the result for this particular query.
+ The cache is an alist of the form:
+ ((((PATTERN . MAXNAMES) . SCALABLE) (FONTNAME . WIDTH) ...) ...) */
+ tem = XCDR (dpyinfo->name_list_element);
+ key = Fcons (Fcons (pattern, make_number (maxnames)),
+ allow_scalable_fonts_p ? Qt : Qnil);
+ list = Fassoc (key, tem);
+ if (!NILP (list))
+ {
+ list = Fcdr_safe (list);
+ /* We have a cashed list. Don't have to get the list again. */
+ goto label_cached;
+ }
+
+ /* At first, put PATTERN in the cache. */
+
+ BLOCK_INPUT;
+ count = x_catch_errors (dpy);
+
+ if (try_XLoadQueryFont)
+ {
+ XFontStruct *font;
+ unsigned long value;
+
+ font = XLoadQueryFont (dpy, SDATA (pattern));
+ if (x_had_errors_p (dpy))
+ {
+ /* This error is perhaps due to insufficient memory on X
+ server. Let's just ignore it. */
+ font = NULL;
+ x_clear_errors (dpy);
+ }
+
+ if (font
+ && XGetFontProperty (font, XA_FONT, &value))
+ {
+ char *name = (char *) XGetAtomName (dpy, (Atom) value);
+ int len = strlen (name);
+ char *tmp;
+
+ /* If DXPC (a Differential X Protocol Compressor)
+ Ver.3.7 is running, XGetAtomName will return null
+ string. We must avoid such a name. */
+ if (len == 0)
+ try_XLoadQueryFont = 0;
+ else
+ {
+ num_fonts = 1;
+ names = (char **) alloca (sizeof (char *));
+ /* Some systems only allow alloca assigned to a
+ simple var. */
+ tmp = (char *) alloca (len + 1); names[0] = tmp;
+ bcopy (name, names[0], len + 1);
+ XFree (name);
+ }
+ }
+ else
+ try_XLoadQueryFont = 0;
+
+ if (font)
+ XFreeFont (dpy, font);
+ }
+
+ if (!try_XLoadQueryFont)
+ {
+ /* We try at least 10 fonts because XListFonts will return
+ auto-scaled fonts at the head. */
+ if (maxnames < 0)
+ {
+ int limit;
+
+ for (limit = 500;;)
+ {
+ names = XListFonts (dpy, SDATA (pattern), limit,
&num_fonts);
+ if (num_fonts == limit)
+ {
+ BLOCK_INPUT;
+ XFreeFontNames (names);
+ UNBLOCK_INPUT;
+ limit *= 2;
+ }
+ else
+ break;
+ }
+ }
+ else
+ names = XListFonts (dpy, SDATA (pattern), max (maxnames, 10),
+ &num_fonts);
+
+ if (x_had_errors_p (dpy))
+ {
+ /* This error is perhaps due to insufficient memory on X
+ server. Let's just ignore it. */
+ names = NULL;
+ x_clear_errors (dpy);
+ }
+ }
+
+ x_uncatch_errors (dpy, count);
+ UNBLOCK_INPUT;
+
+ if (names)
+ {
+ int i;
+
+ /* Make a list of all the fonts we got back.
+ Store that in the font cache for the display. */
+ for (i = 0; i < num_fonts; i++)
+ {
+ int width = 0;
+ char *p = names[i];
+ int average_width = -1, dashes = 0;
+
+ /* Count the number of dashes in NAMES[I]. If there are
+ 14 dashes, and the field value following 12th dash
+ (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
+ is usually too ugly to be used for editing. Let's
+ ignore it. */
+ while (*p)
+ if (*p++ == '-')
+ {
+ dashes++;
+ if (dashes == 7) /* PIXEL_SIZE field */
+ width = atoi (p);
+ else if (dashes == 12) /* AVERAGE_WIDTH field */
+ average_width = atoi (p);
+ }
+
+ if (allow_scalable_fonts_p
+ || dashes < 14 || average_width != 0)
+ {
+ tem = build_string (names[i]);
+ if (NILP (Fassoc (tem, list)))
+ {
+ if (STRINGP (Vx_pixel_size_width_font_regexp)
+ && ((fast_c_string_match_ignore_case
+ (Vx_pixel_size_width_font_regexp, names[i]))
+ >= 0))
+ /* We can set the value of PIXEL_SIZE to the
+ width of this font. */
+ list = Fcons (Fcons (tem, make_number (width)), list);
+ else
+ /* For the moment, width is not known. */
+ list = Fcons (Fcons (tem, Qnil), list);
+ }
+ }
+ }
+
+ if (!try_XLoadQueryFont)
+ {
+ BLOCK_INPUT;
+ XFreeFontNames (names);
+ UNBLOCK_INPUT;
+ }
+ }
+
+ /* Now store the result in the cache. */
+ XSETCDR (dpyinfo->name_list_element,
+ Fcons (Fcons (key, list), XCDR (dpyinfo->name_list_element)));
+
+ label_cached:
+ if (NILP (list)) continue; /* Try the remaining alternatives. */
+
+ newlist = second_best = Qnil;
+ /* Make a list of the fonts that have the right width. */
+ for (; CONSP (list); list = XCDR (list))
+ {
+ int found_size;
+
+ tem = XCAR (list);
+
+ if (!CONSP (tem) || NILP (XCAR (tem)))
+ continue;
+ if (!size)
+ {
+ newlist = Fcons (XCAR (tem), newlist);
+ continue;
+ }
+
+ if (!INTEGERP (XCDR (tem)))
+ {
+ /* Since we have not yet known the size of this font, we
+ must try slow function call XLoadQueryFont. */
+ XFontStruct *thisinfo;
+
+ BLOCK_INPUT;
+ count = x_catch_errors (dpy);
+ thisinfo = XLoadQueryFont (dpy,
+ SDATA (XCAR (tem)));
+ if (x_had_errors_p (dpy))
+ {
+ /* This error is perhaps due to insufficient memory on X
+ server. Let's just ignore it. */
+ thisinfo = NULL;
+ x_clear_errors (dpy);
+ }
+ x_uncatch_errors (dpy, count);
+ UNBLOCK_INPUT;
+
+ if (thisinfo)
+ {
+ XSETCDR (tem,
+ (thisinfo->min_bounds.width == 0
+ ? make_number (0)
+ : make_number (thisinfo->max_bounds.width)));
+ BLOCK_INPUT;
+ XFreeFont (dpy, thisinfo);
+ UNBLOCK_INPUT;
+ }
+ else
+ /* For unknown reason, the previous call of XListFont had
+ returned a font which can't be opened. Record the size
+ as 0 not to try to open it again. */
+ XSETCDR (tem, make_number (0));
+ }
+
+ found_size = XINT (XCDR (tem));
+ if (found_size == size)
+ newlist = Fcons (XCAR (tem), newlist);
+ else if (found_size > 0)
+ {
+ if (NILP (second_best))
+ second_best = tem;
+ else if (found_size < size)
+ {
+ if (XINT (XCDR (second_best)) > size
+ || XINT (XCDR (second_best)) < found_size)
+ second_best = tem;
+ }
+ else
+ {
+ if (XINT (XCDR (second_best)) > size
+ && XINT (XCDR (second_best)) > found_size)
+ second_best = tem;
+ }
+ }
+ }
+ if (!NILP (newlist))
+ break;
+ else if (!NILP (second_best))
+ {
+ newlist = Fcons (XCAR (second_best), Qnil);
+ break;
+ }
+ }
+
+ return newlist;
+ }
+
+
+ #if GLYPH_DEBUG
+
+ /* Check that FONT is valid on frame F. It is if it can be found in F's
+ font table. */
+
+ static void
+ x_check_font (f, font)
+ struct frame *f;
+ XFontStruct *font;
+ {
+ int i;
+ struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+
+ xassert (font != NULL);
+
+ for (i = 0; i < dpyinfo->n_fonts; i++)
+ if (dpyinfo->font_table[i].name
+ && font == dpyinfo->font_table[i].font)
+ break;
+
+ xassert (i < dpyinfo->n_fonts);
+ }
+
+ #endif /* GLYPH_DEBUG != 0 */
+
+ /* Set *W to the minimum width, *H to the minimum font height of FONT.
+ Note: There are (broken) X fonts out there with invalid XFontStruct
+ min_bounds contents. For example, address@hidden reports that
+ "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
+ have font->min_bounds.width == 0. */
+
+ static INLINE void
+ x_font_min_bounds (font, w, h)
+ XFontStruct *font;
+ int *w, *h;
+ {
+ *h = FONT_HEIGHT (font);
+ *w = font->min_bounds.width;
+
+ /* Try to handle the case where FONT->min_bounds has invalid
+ contents. Since the only font known to have invalid min_bounds
+ is fixed-width, use max_bounds if min_bounds seems to be invalid. */
+ if (*w <= 0)
+ *w = font->max_bounds.width;
+ }
+
+
+ /* Compute the smallest character width and smallest font height over
+ all fonts available on frame F. Set the members smallest_char_width
+ and smallest_font_height in F's x_display_info structure to
+ the values computed. Value is non-zero if smallest_font_height or
+ smallest_char_width become smaller than they were before. */
+
+ static int
+ x_compute_min_glyph_bounds (f)
+ struct frame *f;
+ {
+ int i;
+ struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ XFontStruct *font;
+ int old_width = dpyinfo->smallest_char_width;
+ int old_height = dpyinfo->smallest_font_height;
+
+ dpyinfo->smallest_font_height = 100000;
+ dpyinfo->smallest_char_width = 100000;
+
+ for (i = 0; i < dpyinfo->n_fonts; ++i)
+ if (dpyinfo->font_table[i].name)
+ {
+ struct font_info *fontp = dpyinfo->font_table + i;
+ int w, h;
+
+ font = (XFontStruct *) fontp->font;
+ xassert (font != (XFontStruct *) ~0);
+ x_font_min_bounds (font, &w, &h);
+
+ dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
+ dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
+ }
+
+ xassert (dpyinfo->smallest_char_width > 0
+ && dpyinfo->smallest_font_height > 0);
+
+ return (dpyinfo->n_fonts == 1
+ || dpyinfo->smallest_char_width < old_width
+ || dpyinfo->smallest_font_height < old_height);
+ }
+
+
+ /* Load font named FONTNAME of the size SIZE for frame F, and return a
+ pointer to the structure font_info while allocating it dynamically.
+ If SIZE is 0, load any size of font.
+ If loading is failed, return NULL. */
+
+ struct font_info *
+ x_load_font (f, fontname, size)
+ struct frame *f;
+ register char *fontname;
+ int size;
+ {
+ struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ Lisp_Object font_names;
+ int count;
+
+ /* 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 names. */
+ font_names = x_list_fonts (f, build_string (fontname), size, 1);
+
+ if (!NILP (font_names))
+ {
+ Lisp_Object tail;
+ int i;
+
+ for (i = 0; i < dpyinfo->n_fonts; i++)
+ for (tail = font_names; CONSP (tail); tail = XCDR (tail))
+ if (dpyinfo->font_table[i].name
+ && (!strcmp (dpyinfo->font_table[i].name,
+ SDATA (XCAR (tail)))
+ || !strcmp (dpyinfo->font_table[i].full_name,
+ SDATA (XCAR (tail)))))
+ return (dpyinfo->font_table + i);
+ }
+
+ /* Load the font and add it to the table. */
+ {
+ char *full_name;
+ XFontStruct *font;
+ struct font_info *fontp;
+ unsigned long value;
+ int i;
+
+ /* If we have found fonts by x_list_font, load one of them. If
+ not, we still try to load a font by the name given as FONTNAME
+ because XListFonts (called in x_list_font) of some X server has
+ a bug of not finding a font even if the font surely exists and
+ is loadable by XLoadQueryFont. */
+ if (size > 0 && !NILP (font_names))
+ fontname = (char *) SDATA (XCAR (font_names));
+
+ BLOCK_INPUT;
+ count = x_catch_errors (FRAME_X_DISPLAY (f));
+ font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
+ if (x_had_errors_p (FRAME_X_DISPLAY (f)))
+ {
+ /* This error is perhaps due to insufficient memory on X
+ server. Let's just ignore it. */
+ font = NULL;
+ x_clear_errors (FRAME_X_DISPLAY (f));
+ }
+ x_uncatch_errors (FRAME_X_DISPLAY (f), count);
+ UNBLOCK_INPUT;
+ if (!font)
+ return NULL;
+
+ /* Find a free slot in the font table. */
+ for (i = 0; i < dpyinfo->n_fonts; ++i)
+ if (dpyinfo->font_table[i].name == NULL)
+ break;
+
+ /* If no free slot found, maybe enlarge the font table. */
+ if (i == dpyinfo->n_fonts
+ && dpyinfo->n_fonts == dpyinfo->font_table_size)
+ {
+ int sz;
+ dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
+ sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
+ dpyinfo->font_table
+ = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
+ }
+
+ fontp = dpyinfo->font_table + i;
+ if (i == dpyinfo->n_fonts)
+ ++dpyinfo->n_fonts;
+
+ /* Now fill in the slots of *FONTP. */
+ BLOCK_INPUT;
+ fontp->font = font;
+ fontp->font_idx = i;
+ fontp->charset = -1; /* fs_load_font sets it. */
+ fontp->name = (char *) xmalloc (strlen (fontname) + 1);
+ bcopy (fontname, fontp->name, strlen (fontname) + 1);
+
+ /* Try to get the full name of FONT. Put it in FULL_NAME. */
+ full_name = 0;
+ if (XGetFontProperty (font, XA_FONT, &value))
+ {
+ char *name = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
+ char *p = name;
+ int dashes = 0;
+
+ /* Count the number of dashes in the "full name".
+ If it is too few, this isn't really the font's full name,
+ so don't use it.
+ In X11R4, the fonts did not come with their canonical names
+ stored in them. */
+ while (*p)
+ {
+ if (*p == '-')
+ dashes++;
+ p++;
+ }
+
+ if (dashes >= 13)
+ {
+ full_name = (char *) xmalloc (p - name + 1);
+ bcopy (name, full_name, p - name + 1);
+ }
+
+ XFree (name);
+ }
+
+ if (full_name != 0)
+ fontp->full_name = full_name;
+ else
+ fontp->full_name = fontp->name;
+
+ fontp->size = font->max_bounds.width;
+ fontp->height = FONT_HEIGHT (font);
+
+ if (NILP (font_names))
+ {
+ /* We come here because of a bug of XListFonts mentioned at
+ the head of this block. Let's store this information in
+ the cache for x_list_fonts. */
+ Lisp_Object lispy_name = build_string (fontname);
+ Lisp_Object lispy_full_name = build_string (fontp->full_name);
+ Lisp_Object key = Fcons (Fcons (lispy_name, make_number (256)),
+ Qnil);
+
+ XSETCDR (dpyinfo->name_list_element,
+ Fcons (Fcons (key,
+ Fcons (Fcons (lispy_full_name,
+ make_number (fontp->size)),
+ Qnil)),
+ XCDR (dpyinfo->name_list_element)));
+ if (full_name)
+ {
+ key = Fcons (Fcons (lispy_full_name, make_number (256)),
+ Qnil);
+ XSETCDR (dpyinfo->name_list_element,
+ Fcons (Fcons (key,
+ Fcons (Fcons (lispy_full_name,
+ make_number (fontp->size)),
+ Qnil)),
+ XCDR (dpyinfo->name_list_element)));
+ }
+ }
+
+ /* The slot `encoding' specifies how to map a character
+ code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
+ the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
+ (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
+ 2:0xA020..0xFF7F). For the moment, we don't know which charset
+ uses this font. So, we set information in fontp->encoding_type
+ which is never used by any charset. If mapping can't be
+ decided, set FONT_ENCODING_NOT_DECIDED. */
+ fontp->encoding_type
+ = (font->max_byte1 == 0
+ /* 1-byte font */
+ ? (font->min_char_or_byte2 < 0x80
+ ? (font->max_char_or_byte2 < 0x80
+ ? 0 /* 0x20..0x7F */
+ : FONT_ENCODING_NOT_DECIDED) /* 0x20..0xFF */
+ : 1) /* 0xA0..0xFF */
+ /* 2-byte font */
+ : (font->min_byte1 < 0x80
+ ? (font->max_byte1 < 0x80
+ ? (font->min_char_or_byte2 < 0x80
+ ? (font->max_char_or_byte2 < 0x80
+ ? 0 /* 0x2020..0x7F7F */
+ : FONT_ENCODING_NOT_DECIDED) /* 0x2020..0x7FFF */
+ : 3) /* 0x20A0..0x7FFF */
+ : FONT_ENCODING_NOT_DECIDED) /* 0x20??..0xA0?? */
+ : (font->min_char_or_byte2 < 0x80
+ ? (font->max_char_or_byte2 < 0x80
+ ? 2 /* 0xA020..0xFF7F */
+ : FONT_ENCODING_NOT_DECIDED) /* 0xA020..0xFFFF */
+ : 1))); /* 0xA0A0..0xFFFF */
+
+ fontp->baseline_offset
+ = (XGetFontProperty (font, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
+ ? (long) value : 0);
+ fontp->relative_compose
+ = (XGetFontProperty (font, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
+ ? (long) value : 0);
+ fontp->default_ascent
+ = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
+ ? (long) value : 0);
+
+ /* Set global flag fonts_changed_p to non-zero if the font loaded
+ has a character with a smaller width than any other character
+ before, or if the font loaded has a smaller height than any
+ other font loaded before. If this happens, it will make a
+ glyph matrix reallocation necessary. */
+ fonts_changed_p |= x_compute_min_glyph_bounds (f);
+ UNBLOCK_INPUT;
+ return fontp;
+ }
+ }
+
+
+ /* Return a pointer to struct font_info of a font named FONTNAME for
+ frame F. If no such font is loaded, return NULL. */
+
+ struct font_info *
+ x_query_font (f, fontname)
+ struct frame *f;
+ register char *fontname;
+ {
+ struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ int i;
+
+ for (i = 0; i < dpyinfo->n_fonts; i++)
+ if (dpyinfo->font_table[i].name
+ && (!strcmp (dpyinfo->font_table[i].name, fontname)
+ || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
+ return (dpyinfo->font_table + i);
+ return NULL;
+ }
+
+
+ /* Find a CCL program for a font specified by FONTP, and set the member
+ `encoder' of the structure. */
+
+ void
+ x_find_ccl_program (fontp)
+ struct font_info *fontp;
+ {
+ Lisp_Object list, elt;
+
+ elt = Qnil;
+ for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
+ {
+ elt = XCAR (list);
+ if (CONSP (elt)
+ && STRINGP (XCAR (elt))
+ && ((fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
+ >= 0)
+ || (fast_c_string_match_ignore_case (XCAR (elt), fontp->full_name)
+ >= 0)))
+ break;
+ }
+
+ if (! NILP (list))
+ {
+ struct ccl_program *ccl
+ = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
+
+ if (setup_ccl_program (ccl, XCDR (elt)) < 0)
+ xfree (ccl);
+ else
+ fontp->font_encoder = ccl;
+ }
+ }
+
+
+ /* Return a char-table whose elements are t if the font FONT_INFO
+ contains a glyph for the corresponding character, and nil if not.
+
+ Fixme: For the moment, this function works only for fonts whose
+ glyph encoding is the same as Unicode (e.g. ISO10646-1 fonts). */
+
+ Lisp_Object
+ x_get_font_repertory (f, font_info)
+ FRAME_PTR f;
+ struct font_info *font_info;
+ {
+ XFontStruct *font = (XFontStruct *) font_info->font;
+ Lisp_Object table;
+ int min_byte1, max_byte1, min_byte2, max_byte2;
+
+ table = Fmake_char_table (Qnil, Qnil);
+
+ min_byte1 = font->min_byte1;
+ max_byte1 = font->max_byte1;
+ min_byte2 = font->min_char_or_byte2;
+ max_byte2 = font->max_char_or_byte2;
+ if (min_byte1 == 0 && max_byte1 == 0)
+ {
+ if (! font->per_char || font->all_chars_exist == True)
+ char_table_set_range (table, min_byte2, max_byte2, Qt);
+ else
+ {
+ XCharStruct *pcm = font->per_char;
+ int from = -1;
+ int i;
+
+ for (i = min_byte2; i <= max_byte2; i++, pcm++)
+ {
+ if (pcm->width == 0 && pcm->rbearing == pcm->lbearing)
+ {
+ if (from >= 0)
+ {
+ char_table_set_range (table, from, i - 1, Qt);
+ from = -1;
+ }
+ }
+ else if (from < 0)
+ from = i;
+ }
+ if (from >= 0)
+ char_table_set_range (table, from, i - 1, Qt);
+ }
+ }
+ else
+ {
+ if (! font->per_char || font->all_chars_exist == True)
+ {
+ int i;
+
+ for (i = min_byte1; i <= max_byte1; i++)
+ char_table_set_range (table,
+ (i << 8) | min_byte2, (i << 8) | max_byte2,
+ Qt);
+ }
+ else
+ {
+ XCharStruct *pcm = font->per_char;
+ int i;
+
+ for (i = min_byte1; i <= max_byte1; i++)
+ {
+ int from = -1;
+ int j;
+
+ for (j = min_byte2; j <= max_byte2; j++, pcm++)
+ {
+ if (pcm->width == 0 && pcm->rbearing == pcm->lbearing)
+ {
+ if (from >= 0)
+ {
+ char_table_set_range (table, (i << 8) | from,
+ (i << 8) | (j - 1), Qt);
+ from = -1;
+ }
+ }
+ else if (from < 0)
+ from = j;
+ }
+ if (from >= 0)
+ char_table_set_range (table, (i << 8) | from,
+ (i << 8) | (j - 1), Qt);
+ }
+ }
+ }
+
+ return table;
+ }
+
+ /***********************************************************************
+ Initialization
+ ***********************************************************************/
+
+ #ifdef USE_X_TOOLKIT
+ static XrmOptionDescRec emacs_options[] = {
+ {"-geometry", ".geometry", XrmoptionSepArg, NULL},
+ {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"},
+
+ {"-internal-border-width", "*EmacsScreen.internalBorderWidth",
+ XrmoptionSepArg, NULL},
+ {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL},
+
+ {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
+ {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
+ {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL},
+ {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer)
NULL},
+ {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL},
+ {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
+ {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
+ };
+ #endif /* USE_X_TOOLKIT */
+
+ static int x_initialized;
+
+ #ifdef MULTI_KBOARD
+ /* Test whether two display-name strings agree up to the dot that separates
+ the screen number from the server number. */
+ static int
+ same_x_server (name1, name2)
+ const char *name1, *name2;
+ {
+ int seen_colon = 0;
+ const unsigned char *system_name = SDATA (Vsystem_name);
+ int system_name_length = strlen (system_name);
+ int length_until_period = 0;
+
+ while (system_name[length_until_period] != 0
+ && system_name[length_until_period] != '.')
+ length_until_period++;
+
+ /* Treat `unix' like an empty host name. */
+ if (! strncmp (name1, "unix:", 5))
+ name1 += 4;
+ if (! strncmp (name2, "unix:", 5))
+ name2 += 4;
+ /* Treat this host's name like an empty host name. */
+ if (! strncmp (name1, system_name, system_name_length)
+ && name1[system_name_length] == ':')
+ name1 += system_name_length;
+ if (! strncmp (name2, system_name, system_name_length)
+ && name2[system_name_length] == ':')
+ name2 += system_name_length;
+ /* Treat this host's domainless name like an empty host name. */
+ if (! strncmp (name1, system_name, length_until_period)
+ && name1[length_until_period] == ':')
+ name1 += length_until_period;
+ if (! strncmp (name2, system_name, length_until_period)
+ && name2[length_until_period] == ':')
+ name2 += length_until_period;
+
+ for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
+ {
+ if (*name1 == ':')
+ seen_colon++;
+ if (seen_colon && *name1 == '.')
+ return 1;
+ }
+ return (seen_colon
+ && (*name1 == '.' || *name1 == '\0')
+ && (*name2 == '.' || *name2 == '\0'));
+ }
+ #endif
+
+ struct x_display_info *
+ x_term_init (display_name, xrm_option, resource_name)
+ Lisp_Object display_name;
+ char *xrm_option;
+ char *resource_name;
+ {
+ int connection;
+ Display *dpy;
+ struct x_display_info *dpyinfo;
+ XrmDatabase xrdb;
+
+ BLOCK_INPUT;
+
+ if (!x_initialized)
+ {
+ x_initialize ();
+ x_initialized = 1;
+ }
+
+ #ifdef USE_GTK
+ {
+ #define NUM_ARGV 10
+ int argc;
+ char *argv[NUM_ARGV];
+ char **argv2 = argv;
+ GdkAtom atom;
+
+ /* GTK 2.0 can only handle one display, GTK 2.2 can handle more
+ than one, but this remains to be implemented. */
+ if (x_initialized > 1)
+ return 0;
+
+ x_initialized++;
+
+ for (argc = 0; argc < NUM_ARGV; ++argc)
+ argv[argc] = 0;
+
+ argc = 0;
+ argv[argc++] = initial_argv[0];
+
+ if (! NILP (display_name))
+ {
+ argv[argc++] = "--display";
+ argv[argc++] = SDATA (display_name);
+ }
+
+ argv[argc++] = "--name";
+ argv[argc++] = resource_name;
+
+ #ifdef HAVE_X11R5
+ XSetLocaleModifiers ("");
+ #endif
+
+ gtk_init (&argc, &argv2);
+
+ /* gtk_init does set_locale. We must fix locale after calling it. */
+ fixup_locale ();
+ xg_initialize ();
+
+ dpy = GDK_DISPLAY ();
+
+ /* NULL window -> events for all windows go to our function */
+ gdk_window_add_filter (NULL, event_handler_gdk, NULL);
+
+ /* Load our own gtkrc if it exists. */
+ {
+ struct gcpro gcpro1, gcpro2;
+ char *file = "~/.emacs.d/gtkrc";
+ Lisp_Object s, abs_file;
+
+ GCPRO2 (s, abs_file);
+ s = make_string (file, strlen (file));
+ abs_file = Fexpand_file_name(s, Qnil);
+
+ if (! NILP (abs_file) && Ffile_readable_p (abs_file))
+ gtk_rc_parse (SDATA (abs_file));
+
+ UNGCPRO;
+ }
+
+ XSetErrorHandler (x_error_handler);
+ XSetIOErrorHandler (x_io_error_quitter);
+ }
+ #else /* not USE_GTK */
+ #ifdef USE_X_TOOLKIT
+ /* address@hidden reports that this causes
+ errors with X11R5:
+ X protocol error: BadAtom (invalid Atom parameter)
+ on protocol request 18skiloaf.
+ So let's not use it until R6. */
+ #ifdef HAVE_X11XTR6
+ XtSetLanguageProc (NULL, NULL, NULL);
+ #endif
+
+ {
+ int argc = 0;
+ char *argv[3];
+
+ argv[0] = "";
+ argc = 1;
+ if (xrm_option)
+ {
+ argv[argc++] = "-xrm";
+ argv[argc++] = xrm_option;
+ }
+ turn_on_atimers (0);
+ dpy = XtOpenDisplay (Xt_app_con, SDATA (display_name),
+ resource_name, EMACS_CLASS,
+ emacs_options, XtNumber (emacs_options),
+ &argc, argv);
+ turn_on_atimers (1);
+
+ #ifdef HAVE_X11XTR6
+ /* I think this is to compensate for XtSetLanguageProc. */
+ fixup_locale ();
+ #endif
+ }
+
+ #else /* not USE_X_TOOLKIT */
+ #ifdef HAVE_X11R5
+ XSetLocaleModifiers ("");
+ #endif
+ dpy = XOpenDisplay (SDATA (display_name));
+ #endif /* not USE_X_TOOLKIT */
+ #endif /* not USE_GTK*/
+
+ /* Detect failure. */
+ if (dpy == 0)
+ {
+ UNBLOCK_INPUT;
+ return 0;
+ }
+
+ /* We have definitely succeeded. Record the new connection. */
+
+ dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct
x_display_info));
+ bzero (dpyinfo, sizeof *dpyinfo);
+
+ #ifdef MULTI_KBOARD
+ {
+ struct x_display_info *share;
+ Lisp_Object tail;
+
+ for (share = x_display_list, tail = x_display_name_list; share;
+ share = share->next, tail = XCDR (tail))
+ if (same_x_server (SDATA (XCAR (XCAR (tail))),
+ SDATA (display_name)))
+ break;
+ if (share)
+ dpyinfo->kboard = share->kboard;
+ else
+ {
+ dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
+ init_kboard (dpyinfo->kboard);
+ if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
+ {
+ char *vendor = ServerVendor (dpy);
+ UNBLOCK_INPUT;
+ dpyinfo->kboard->Vsystem_key_alist
+ = call1 (Qvendor_specific_keysyms,
+ build_string (vendor ? vendor : ""));
+ BLOCK_INPUT;
+ }
+
+ dpyinfo->kboard->next_kboard = all_kboards;
+ all_kboards = dpyinfo->kboard;
+ /* Don't let the initial kboard remain current longer than necessary.
+ That would cause problems if a file loaded on startup tries to
+ prompt in the mini-buffer. */
+ if (current_kboard == initial_kboard)
+ current_kboard = dpyinfo->kboard;
+ }
+ dpyinfo->kboard->reference_count++;
+ }
+ #endif
+
+ /* Put this display on the chain. */
+ dpyinfo->next = x_display_list;
+ x_display_list = dpyinfo;
+
+ /* Put it on x_display_name_list as well, to keep them parallel. */
+ x_display_name_list = Fcons (Fcons (display_name, Qnil),
+ x_display_name_list);
+ dpyinfo->name_list_element = XCAR (x_display_name_list);
+
+ dpyinfo->display = dpy;
+
+ #if 0
+ XSetAfterFunction (x_current_display, x_trace_wire);
+ #endif /* ! 0 */
+
+ dpyinfo->x_id_name
+ = (char *) xmalloc (SBYTES (Vinvocation_name)
+ + SBYTES (Vsystem_name)
+ + 2);
+ sprintf (dpyinfo->x_id_name, "address@hidden",
+ SDATA (Vinvocation_name), SDATA (Vsystem_name));
+
+ /* Figure out which modifier bits mean what. */
+ x_find_modifier_meanings (dpyinfo);
+
+ /* Get the scroll bar cursor. */
+ dpyinfo->vertical_scroll_bar_cursor
+ = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow);
+
+ xrdb = x_load_resources (dpyinfo->display, xrm_option,
+ resource_name, EMACS_CLASS);
+ #ifdef HAVE_XRMSETDATABASE
+ XrmSetDatabase (dpyinfo->display, xrdb);
+ #else
+ dpyinfo->display->db = xrdb;
+ #endif
+ /* Put the rdb where we can find it in a way that works on
+ all versions. */
+ dpyinfo->xrdb = xrdb;
+
+ dpyinfo->screen = ScreenOfDisplay (dpyinfo->display,
+ DefaultScreen (dpyinfo->display));
+ select_visual (dpyinfo);
+ dpyinfo->cmap = DefaultColormapOfScreen (dpyinfo->screen);
+ dpyinfo->height = HeightOfScreen (dpyinfo->screen);
+ dpyinfo->width = WidthOfScreen (dpyinfo->screen);
+ dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen);
+ dpyinfo->grabbed = 0;
+ dpyinfo->reference_count = 0;
+ dpyinfo->icon_bitmap_id = -1;
+ dpyinfo->font_table = NULL;
+ dpyinfo->n_fonts = 0;
+ dpyinfo->font_table_size = 0;
+ dpyinfo->bitmaps = 0;
+ dpyinfo->bitmaps_size = 0;
+ dpyinfo->bitmaps_last = 0;
+ dpyinfo->scratch_cursor_gc = 0;
+ dpyinfo->mouse_face_mouse_frame = 0;
+ dpyinfo->mouse_face_deferred_gc = 0;
+ dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
+ dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
+ dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
+ dpyinfo->mouse_face_window = Qnil;
+ dpyinfo->mouse_face_overlay = Qnil;
+ dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
+ dpyinfo->mouse_face_defer = 0;
+ dpyinfo->mouse_face_hidden = 0;
+ dpyinfo->x_focus_frame = 0;
+ dpyinfo->x_focus_event_frame = 0;
+ dpyinfo->x_highlight_frame = 0;
+ dpyinfo->image_cache = make_image_cache ();
+
+ /* See if a private colormap is requested. */
+ if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
+ {
+ if (dpyinfo->visual->class == PseudoColor)
+ {
+ Lisp_Object value;
+ value = display_x_get_resource (dpyinfo,
+ build_string ("privateColormap"),
+ build_string ("PrivateColormap"),
+ Qnil, Qnil);
+ if (STRINGP (value)
+ && (!strcmp (SDATA (value), "true")
+ || !strcmp (SDATA (value), "on")))
+ dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display,
dpyinfo->cmap);
+ }
+ }
+ else
+ dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window,
+ dpyinfo->visual, AllocNone);
+
+ {
+ int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
+ double pixels = DisplayHeight (dpyinfo->display, screen_number);
+ double mm = DisplayHeightMM (dpyinfo->display, screen_number);
+ dpyinfo->resy = pixels * 25.4 / mm;
+ pixels = DisplayWidth (dpyinfo->display, screen_number);
+ mm = DisplayWidthMM (dpyinfo->display, screen_number);
+ dpyinfo->resx = pixels * 25.4 / mm;
+ }
+
+ dpyinfo->Xatom_wm_protocols
+ = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
+ dpyinfo->Xatom_wm_take_focus
+ = XInternAtom (dpyinfo->display, "WM_TAKE_FOCUS", False);
+ dpyinfo->Xatom_wm_save_yourself
+ = XInternAtom (dpyinfo->display, "WM_SAVE_YOURSELF", False);
+ dpyinfo->Xatom_wm_delete_window
+ = XInternAtom (dpyinfo->display, "WM_DELETE_WINDOW", False);
+ dpyinfo->Xatom_wm_change_state
+ = XInternAtom (dpyinfo->display, "WM_CHANGE_STATE", False);
+ dpyinfo->Xatom_wm_configure_denied
+ = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False);
+ dpyinfo->Xatom_wm_window_moved
+ = XInternAtom (dpyinfo->display, "WM_MOVED", False);
+ dpyinfo->Xatom_editres
+ = XInternAtom (dpyinfo->display, "Editres", False);
+ dpyinfo->Xatom_CLIPBOARD
+ = XInternAtom (dpyinfo->display, "CLIPBOARD", False);
+ dpyinfo->Xatom_TIMESTAMP
+ = XInternAtom (dpyinfo->display, "TIMESTAMP", False);
+ dpyinfo->Xatom_TEXT
+ = XInternAtom (dpyinfo->display, "TEXT", False);
+ dpyinfo->Xatom_COMPOUND_TEXT
+ = XInternAtom (dpyinfo->display, "COMPOUND_TEXT", False);
+ dpyinfo->Xatom_UTF8_STRING
+ = XInternAtom (dpyinfo->display, "UTF8_STRING", False);
+ dpyinfo->Xatom_DELETE
+ = XInternAtom (dpyinfo->display, "DELETE", False);
+ dpyinfo->Xatom_MULTIPLE
+ = XInternAtom (dpyinfo->display, "MULTIPLE", False);
+ dpyinfo->Xatom_INCR
+ = XInternAtom (dpyinfo->display, "INCR", False);
+ dpyinfo->Xatom_EMACS_TMP
+ = XInternAtom (dpyinfo->display, "_EMACS_TMP_", False);
+ dpyinfo->Xatom_TARGETS
+ = XInternAtom (dpyinfo->display, "TARGETS", False);
+ dpyinfo->Xatom_NULL
+ = XInternAtom (dpyinfo->display, "NULL", False);
+ dpyinfo->Xatom_ATOM_PAIR
+ = XInternAtom (dpyinfo->display, "ATOM_PAIR", False);
+ /* For properties of font. */
+ dpyinfo->Xatom_PIXEL_SIZE
+ = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False);
+ dpyinfo->Xatom_MULE_BASELINE_OFFSET
+ = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False);
+ dpyinfo->Xatom_MULE_RELATIVE_COMPOSE
+ = XInternAtom (dpyinfo->display, "_MULE_RELATIVE_COMPOSE", False);
+ dpyinfo->Xatom_MULE_DEFAULT_ASCENT
+ = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
+
+ /* Ghostscript support. */
+ dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
+ dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
+
+ dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
+ False);
+
+ dpyinfo->cut_buffers_initialized = 0;
+
+ connection = ConnectionNumber (dpyinfo->display);
+ dpyinfo->connection = connection;
+
+ {
+ char null_bits[1];
+
+ null_bits[0] = 0x00;
+
+ dpyinfo->null_pixel
+ = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
+ null_bits, 1, 1, (long) 0, (long) 0,
+ 1);
+ }
+
+ {
+ extern int gray_bitmap_width, gray_bitmap_height;
+ extern char *gray_bitmap_bits;
+ dpyinfo->gray
+ = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
+ gray_bitmap_bits,
+ gray_bitmap_width, gray_bitmap_height,
+ (unsigned long) 1, (unsigned long) 0, 1);
+ }
+
+ #ifdef HAVE_X_I18N
+ xim_initialize (dpyinfo, resource_name);
+ #endif
+
+ #ifdef subprocesses
+ /* This is only needed for distinguishing keyboard and process input. */
+ if (connection != 0)
+ add_keyboard_wait_descriptor (connection);
+ #endif
+
+ #ifndef F_SETOWN_BUG
+ #ifdef F_SETOWN
+ #ifdef F_SETOWN_SOCK_NEG
+ /* stdin is a socket here */
+ fcntl (connection, F_SETOWN, -getpid ());
+ #else /* ! defined (F_SETOWN_SOCK_NEG) */
+ fcntl (connection, F_SETOWN, getpid ());
+ #endif /* ! defined (F_SETOWN_SOCK_NEG) */
+ #endif /* ! defined (F_SETOWN) */
+ #endif /* F_SETOWN_BUG */
+
+ #ifdef SIGIO
+ if (interrupt_input)
+ init_sigio (connection);
+ #endif /* ! defined (SIGIO) */
+
+ #ifdef USE_LUCID
+ #ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer. */
+ /* Make sure that we have a valid font for dialog boxes
+ so that Xt does not crash. */
+ {
+ Display *dpy = dpyinfo->display;
+ XrmValue d, fr, to;
+ Font font;
+ int count;
+
+ d.addr = (XPointer)&dpy;
+ d.size = sizeof (Display *);
+ fr.addr = XtDefaultFont;
+ fr.size = sizeof (XtDefaultFont);
+ to.size = sizeof (Font *);
+ to.addr = (XPointer)&font;
+ count = x_catch_errors (dpy);
+ if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
+ abort ();
+ if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
+ XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
+ x_uncatch_errors (dpy, count);
+ }
+ #endif
+ #endif
+
+ /* See if we should run in synchronous mode. This is useful
+ for debugging X code. */
+ {
+ Lisp_Object value;
+ value = display_x_get_resource (dpyinfo,
+ build_string ("synchronous"),
+ build_string ("Synchronous"),
+ Qnil, Qnil);
+ if (STRINGP (value)
+ && (!strcmp (SDATA (value), "true")
+ || !strcmp (SDATA (value), "on")))
+ XSynchronize (dpyinfo->display, True);
+ }
+
+ {
+ Lisp_Object value;
+ value = display_x_get_resource (dpyinfo,
+ build_string ("useXIM"),
+ build_string ("UseXIM"),
+ Qnil, Qnil);
+ #ifdef USE_XIM
+ if (STRINGP (value)
+ && (!strcmp (XSTRING (value)->data, "false")
+ || !strcmp (XSTRING (value)->data, "off")))
+ use_xim = 0;
+ #else
+ if (STRINGP (value)
+ && (!strcmp (XSTRING (value)->data, "true")
+ || !strcmp (XSTRING (value)->data, "on")))
+ use_xim = 1;
+ #endif
+ }
+
+ UNBLOCK_INPUT;
+
+ return dpyinfo;
+ }
+
+ /* Get rid of display DPYINFO, assuming all frames are already gone,
+ and without sending any more commands to the X server. */
+
+ void
+ x_delete_display (dpyinfo)
+ struct x_display_info *dpyinfo;
+ {
+ delete_keyboard_wait_descriptor (dpyinfo->connection);
+
+ /* Discard this display from x_display_name_list and x_display_list.
+ We can't use Fdelq because that can quit. */
+ if (! NILP (x_display_name_list)
+ && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
+ x_display_name_list = XCDR (x_display_name_list);
+ else
+ {
+ Lisp_Object tail;
+
+ tail = x_display_name_list;
+ while (CONSP (tail) && CONSP (XCDR (tail)))
+ {
+ if (EQ (XCAR (XCDR (tail)), dpyinfo->name_list_element))
+ {
+ XSETCDR (tail, XCDR (XCDR (tail)));
+ break;
+ }
+ tail = XCDR (tail);
+ }
+ }
+
+ if (next_noop_dpyinfo == dpyinfo)
+ next_noop_dpyinfo = dpyinfo->next;
+
+ if (x_display_list == dpyinfo)
+ x_display_list = dpyinfo->next;
+ else
+ {
+ struct x_display_info *tail;
+
+ for (tail = x_display_list; tail; tail = tail->next)
+ if (tail->next == dpyinfo)
+ tail->next = tail->next->next;
+ }
+
+ #ifndef USE_X_TOOLKIT /* I'm told Xt does this itself. */
+ #ifndef AIX /* On AIX, XCloseDisplay calls this. */
+ XrmDestroyDatabase (dpyinfo->xrdb);
+ #endif
+ #endif
+ #ifdef MULTI_KBOARD
+ if (--dpyinfo->kboard->reference_count == 0)
+ delete_kboard (dpyinfo->kboard);
+ #endif
+ #ifdef HAVE_X_I18N
+ if (dpyinfo->xim)
+ xim_close_dpy (dpyinfo);
+ #endif
+
+ xfree (dpyinfo->font_table);
+ xfree (dpyinfo->x_id_name);
+ xfree (dpyinfo->color_cells);
+ xfree (dpyinfo);
+ }
+
+ #ifdef USE_X_TOOLKIT
+
+ /* Atimer callback function for TIMER. Called every 0.1s to process
+ Xt timeouts, if needed. We must avoid calling XtAppPending as
+ much as possible because that function does an implicit XFlush
+ that slows us down. */
+
+ static void
+ x_process_timeouts (timer)
+ struct atimer *timer;
+ {
+ if (toolkit_scroll_bar_interaction || popup_activated ())
+ {
+ BLOCK_INPUT;
+ while (XtAppPending (Xt_app_con) & XtIMTimer)
+ XtAppProcessEvent (Xt_app_con, XtIMTimer);
+ UNBLOCK_INPUT;
+ }
+ }
+
+ #endif /* USE_X_TOOLKIT */
+
+
+ /* Set up use of X before we make the first connection. */
+
+ extern frame_parm_handler x_frame_parm_handlers[];
+
+ static struct redisplay_interface x_redisplay_interface =
+ {
+ x_frame_parm_handlers,
+ x_produce_glyphs,
+ x_write_glyphs,
+ x_insert_glyphs,
+ x_clear_end_of_line,
+ x_scroll_run,
+ x_after_update_window_line,
+ x_update_window_begin,
+ x_update_window_end,
+ x_cursor_to,
+ x_flush,
+ #ifndef XFlush
+ x_flush,
+ #else
+ 0, /* flush_display_optional */
+ #endif
+ x_clear_window_mouse_face,
+ x_get_glyph_overhangs,
+ x_fix_overlapping_area,
+ x_draw_fringe_bitmap,
+ x_per_char_metric,
+ x_encode_char,
+ x_compute_glyph_string_overhangs,
+ x_draw_glyph_string,
+ x_define_frame_cursor,
+ x_clear_frame_area,
+ x_draw_window_cursor,
+ x_draw_vertical_window_border,
+ x_shift_glyphs_for_insert
+ };
+
+ void
+ x_initialize ()
+ {
+ rif = &x_redisplay_interface;
+
+ clear_frame_hook = x_clear_frame;
+ ins_del_lines_hook = x_ins_del_lines;
+ delete_glyphs_hook = x_delete_glyphs;
+ ring_bell_hook = XTring_bell;
+ reset_terminal_modes_hook = XTreset_terminal_modes;
+ set_terminal_modes_hook = XTset_terminal_modes;
+ update_begin_hook = x_update_begin;
+ update_end_hook = x_update_end;
+ set_terminal_window_hook = XTset_terminal_window;
+ read_socket_hook = XTread_socket;
+ frame_up_to_date_hook = XTframe_up_to_date;
+ mouse_position_hook = XTmouse_position;
+ frame_rehighlight_hook = XTframe_rehighlight;
+ frame_raise_lower_hook = XTframe_raise_lower;
+ set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
+ condemn_scroll_bars_hook = XTcondemn_scroll_bars;
+ redeem_scroll_bar_hook = XTredeem_scroll_bar;
+ judge_scroll_bars_hook = XTjudge_scroll_bars;
+
+ scroll_region_ok = 1; /* we'll scroll partial frames */
+ char_ins_del_ok = 1;
+ line_ins_del_ok = 1; /* we'll just blt 'em */
+ fast_clear_end_of_line = 1; /* X does this well */
+ memory_below_frame = 0; /* we don't remember what scrolls
+ off the bottom */
+ baud_rate = 19200;
+
+ x_noop_count = 0;
+ last_tool_bar_item = -1;
+ any_help_event_p = 0;
+
+ /* Try to use interrupt input; if we can't, then start polling. */
+ Fset_input_mode (Qt, Qnil, Qt, Qnil);
+
+ #ifdef USE_X_TOOLKIT
+ XtToolkitInitialize ();
+
+ Xt_app_con = XtCreateApplicationContext ();
+
+ /* Register a converter from strings to pixels, which uses
+ Emacs' color allocation infrastructure. */
+ XtAppSetTypeConverter (Xt_app_con,
+ XtRString, XtRPixel, cvt_string_to_pixel,
+ cvt_string_to_pixel_args,
+ XtNumber (cvt_string_to_pixel_args),
+ XtCacheByDisplay, cvt_pixel_dtor);
+
+ XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
+
+ /* Install an asynchronous timer that processes Xt timeout events
+ every 0.1s. This is necessary because some widget sets use
+ timeouts internally, for example the LessTif menu bar, or the
+ Xaw3d scroll bar. When Xt timouts aren't processed, these
+ widgets don't behave normally. */
+ {
+ EMACS_TIME interval;
+ EMACS_SET_SECS_USECS (interval, 0, 100000);
+ start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
+ }
+ #endif
+
+ #ifdef USE_TOOLKIT_SCROLL_BARS
+ #ifndef USE_GTK
+ xaw3d_arrow_scroll = False;
+ xaw3d_pick_top = True;
+ #endif
+ #endif
+
+ /* Note that there is no real way portable across R3/R4 to get the
+ original error handler. */
+ XSetErrorHandler (x_error_handler);
+ XSetIOErrorHandler (x_io_error_quitter);
+
+ /* Disable Window Change signals; they are handled by X events. */
+ #ifdef SIGWINCH
+ signal (SIGWINCH, SIG_DFL);
+ #endif /* SIGWINCH */
+
+ signal (SIGPIPE, x_connection_signal);
+
+ #ifdef HAVE_X_SM
+ x_session_initialize ();
+ #endif
+ }
+
+
+ void
+ syms_of_xterm ()
+ {
+ staticpro (&x_error_message_string);
+ x_error_message_string = Qnil;
+
+ staticpro (&x_display_name_list);
+ x_display_name_list = Qnil;
+
+ staticpro (&last_mouse_scroll_bar);
+ last_mouse_scroll_bar = Qnil;
+
+ staticpro (&Qvendor_specific_keysyms);
+ Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
+
+ staticpro (&Qlatin_1);
+ Qlatin_1 = intern ("latin-1");
+
+ staticpro (&last_mouse_press_frame);
+ last_mouse_press_frame = Qnil;
+
+ DEFVAR_BOOL ("x-use-underline-position-properties",
+ &x_use_underline_position_properties,
+ doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
+ nil means ignore them. If you encounter fonts with bogus
+ UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
+ to 4.1, set this to nil. */);
+ x_use_underline_position_properties = 1;
+
+ DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
+ doc: /* What X toolkit scroll bars Emacs uses.
+ A value of nil means Emacs doesn't use X toolkit scroll bars.
+ Otherwise, value is a symbol describing the X toolkit. */);
+ #ifdef USE_TOOLKIT_SCROLL_BARS
+ #ifdef USE_MOTIF
+ Vx_toolkit_scroll_bars = intern ("motif");
+ #elif defined HAVE_XAW3D
+ Vx_toolkit_scroll_bars = intern ("xaw3d");
+ #elif USE_GTK
+ Vx_toolkit_scroll_bars = intern ("gtk");
+ #else
+ Vx_toolkit_scroll_bars = intern ("xaw");
+ #endif
+ #else
+ Vx_toolkit_scroll_bars = Qnil;
+ #endif
+
+ staticpro (&last_mouse_motion_frame);
+ last_mouse_motion_frame = Qnil;
+
+ Qmodifier_value = intern ("modifier-value");
+ Qalt = intern ("alt");
+ Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
+ Qhyper = intern ("hyper");
+ Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
+ Qmeta = intern ("meta");
+ Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
+ Qsuper = intern ("super");
+ Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
+
+ DEFVAR_LISP ("x-alt-keysym", &Vx_alt_keysym,
+ doc: /* Which keys Emacs uses for the alt modifier.
+ This should be one of the symbols `alt', `hyper', `meta', `super'.
+ For example, `alt' means use the Alt_L and Alt_R keysyms. The default
+ is nil, which is the same as `alt'. */);
+ Vx_alt_keysym = Qnil;
+
+ DEFVAR_LISP ("x-hyper-keysym", &Vx_hyper_keysym,
+ doc: /* Which keys Emacs uses for the hyper modifier.
+ This should be one of the symbols `alt', `hyper', `meta', `super'.
+ For example, `hyper' means use the Hyper_L and Hyper_R keysyms. The
+ default is nil, which is the same as `hyper'. */);
+ Vx_hyper_keysym = Qnil;
+
+ DEFVAR_LISP ("x-meta-keysym", &Vx_meta_keysym,
+ doc: /* Which keys Emacs uses for the meta modifier.
+ This should be one of the symbols `alt', `hyper', `meta', `super'.
+ For example, `meta' means use the Meta_L and Meta_R keysyms. The
+ default is nil, which is the same as `meta'. */);
+ Vx_meta_keysym = Qnil;
+
+ DEFVAR_LISP ("x-super-keysym", &Vx_super_keysym,
+ doc: /* Which keys Emacs uses for the super modifier.
+ This should be one of the symbols `alt', `hyper', `meta', `super'.
+ For example, `super' means use the Super_L and Super_R keysyms. The
+ default is nil, which is the same as `super'. */);
+ Vx_super_keysym = Qnil;
+
+ DEFVAR_LISP ("x-keysym-table", &Vx_keysym_table,
+ doc: /* Hash table of character codes indexed by X keysym codes. */);
+ Vx_keysym_table = make_hash_table (Qeql, make_number (900),
+ make_float (DEFAULT_REHASH_SIZE),
+ make_float (DEFAULT_REHASH_THRESHOLD),
+ Qnil, Qnil, Qnil);
+ }
+
+ #endif /* HAVE_X_WINDOWS */
- [Emacs-diffs] Changes to emacs/src/xterm.c [emacs-unicode-2],
Kenichi Handa <=