X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/b6f91066605cb485be14b61e4cd8dc19faa58184..4e39768886730d67ab7721ec3cf942f7a7041483:/src/xfns.c diff --git a/src/xfns.c b/src/xfns.c index 7210678952..ec89ac7b60 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -1,5 +1,5 @@ /* Functions for the X window system. - Copyright (C) 1989, 92, 93, 94, 95, 96, 1997, 1998, 1999, 2000 + Copyright (C) 1989, 92, 93, 94, 95, 96, 1997, 1998, 1999, 2000, 2001 Free Software Foundation. This file is part of GNU Emacs. @@ -24,6 +24,10 @@ Boston, MA 02111-1307, USA. */ #include #include +#ifdef HAVE_UNISTD_H +#include +#endif + /* This makes the fields of a Display accessible, in Xlib header files. */ #define XLIB_ILLEGAL_ACCESS @@ -107,10 +111,15 @@ extern XFontStruct *xlwmenu_default_font; extern void free_frame_menubar (); extern double atof (); -#endif /* USE_X_TOOLKIT */ +#ifdef USE_MOTIF + +/* LessTif/Motif version info. */ + +static Lisp_Object Vmotif_version_string; + +#endif /* USE_MOTIF */ -#define min(a,b) ((a) < (b) ? (a) : (b)) -#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif /* USE_X_TOOLKIT */ #ifdef HAVE_X11R4 #define MAXREQUEST(dpy) (XMaxRequestSize (dpy)) @@ -124,7 +133,7 @@ extern double atof (); int gray_bitmap_width = gray_width; int gray_bitmap_height = gray_height; -unsigned char *gray_bitmap_bits = gray_bits; +char *gray_bitmap_bits = gray_bits; /* The name we're using in resource queries. Most often "emacs". */ @@ -135,20 +144,25 @@ Lisp_Object Vx_resource_name; Lisp_Object Vx_resource_class; -/* Non-zero means we're allowed to display a busy cursor. */ +/* Non-zero means we're allowed to display an hourglass cursor. */ -int display_busy_cursor_p; +int display_hourglass_p; /* The background and shape of the mouse pointer, and shape when not over text or in the modeline. */ Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape; -Lisp_Object Vx_busy_pointer_shape; +Lisp_Object Vx_hourglass_pointer_shape; /* The shape when over mouse-sensitive text. */ Lisp_Object Vx_sensitive_text_pointer_shape; +/* If non-nil, the pointer shape to indicate that windows can be + dragged horizontally. */ + +Lisp_Object Vx_window_horizontal_drag_shape; + /* Color of chars displayed in cursor box. */ Lisp_Object Vx_cursor_fore_pixel; @@ -169,41 +183,6 @@ Lisp_Object Vx_bitmap_file_path; Lisp_Object Vx_pixel_size_width_font_regexp; -/* Evaluate this expression to rebuild the section of syms_of_xfns - that initializes and staticpros the symbols declared below. Note - that Emacs 18 has a bug that keeps C-x C-e from being able to - evaluate this expression. - -(progn - ;; Accumulate a list of the symbols we want to initialize from the - ;; declarations at the top of the file. - (goto-char (point-min)) - (search-forward "/\*&&& symbols declared here &&&*\/\n") - (let (symbol-list) - (while (looking-at "Lisp_Object \\(Q[a-z_]+\\)") - (setq symbol-list - (cons (buffer-substring (match-beginning 1) (match-end 1)) - symbol-list)) - (forward-line 1)) - (setq symbol-list (nreverse symbol-list)) - ;; Delete the section of syms_of_... where we initialize the symbols. - (search-forward "\n /\*&&& init symbols here &&&*\/\n") - (let ((start (point))) - (while (looking-at "^ Q") - (forward-line 2)) - (kill-region start (point))) - ;; Write a new symbol initialization section. - (while symbol-list - (insert (format " %s = intern (\"" (car symbol-list))) - (let ((start (point))) - (insert (substring (car symbol-list) 1)) - (subst-char-in-region start (point) ?_ ?-)) - (insert (format "\");\n staticpro (&%s);\n" (car symbol-list))) - (setq symbol-list (cdr symbol-list))))) - - */ - -/*&&& symbols declared here &&&*/ Lisp_Object Qauto_raise; Lisp_Object Qauto_lower; Lisp_Object Qbar; @@ -238,7 +217,8 @@ Lisp_Object Quser_size; extern Lisp_Object Qdisplay; Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background; Lisp_Object Qscreen_gamma, Qline_spacing, Qcenter; -Lisp_Object Qcompound_text; +Lisp_Object Qcompound_text, Qcancel_timer; +Lisp_Object Qwait_for_wm; /* The below are defined in frame.c. */ @@ -250,6 +230,11 @@ extern Lisp_Object Vwindow_system_version; Lisp_Object Qface_set_after_frame_default; +#if GLYPH_DEBUG +int image_cache_refcount, dpyinfo_refcount; +#endif + + /* Error if we are not connected to X. */ @@ -280,7 +265,7 @@ check_x_frame (frame) if (NILP (frame)) frame = selected_frame; - CHECK_LIVE_FRAME (frame, 0); + CHECK_LIVE_FRAME (frame); f = XFRAME (frame); if (! FRAME_X_P (f)) error ("Non-X frame used"); @@ -314,7 +299,7 @@ check_x_display_info (frame) { FRAME_PTR f; - CHECK_LIVE_FRAME (frame, 0); + CHECK_LIVE_FRAME (frame); f = XFRAME (frame); if (! FRAME_X_P (f)) error ("Non-X frame used"); @@ -346,7 +331,7 @@ x_window_to_frame (dpyinfo, wdesc) f = XFRAME (frame); if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo) continue; - if (f->output_data.x->busy_window == wdesc) + if (f->output_data.x->hourglass_window == wdesc) return f; #ifdef USE_X_TOOLKIT if ((f->output_data.x->edit_widget @@ -390,7 +375,7 @@ x_any_window_to_frame (dpyinfo, wdesc) { /* This frame matches if the window is any of its widgets. */ x = f->output_data.x; - if (x->busy_window == wdesc) + if (x->hourglass_window == wdesc) found = f; else if (x->widget) { @@ -432,7 +417,7 @@ x_non_menubar_window_to_frame (dpyinfo, wdesc) continue; x = f->output_data.x; /* This frame matches if the window is any of its widgets. */ - if (x->busy_window == wdesc) + if (x->hourglass_window == wdesc) return f; else if (x->widget) { @@ -660,7 +645,7 @@ x_create_bitmap_from_file (f, file) } /* Search bitmap-file-path for the file, if appropriate. */ - fd = openp (Vx_bitmap_file_path, file, "", &found, 0); + fd = openp (Vx_bitmap_file_path, file, Qnil, &found, 0); if (fd < 0) return -1; emacs_close (fd); @@ -741,11 +726,13 @@ struct x_frame_parm_table void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object)); }; +static Lisp_Object unwind_create_frame P_ ((Lisp_Object)); +static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object)); static void x_change_window_heights P_ ((Lisp_Object, int)); static void x_disable_image P_ ((struct frame *, struct image *)); -static void x_create_im P_ ((struct frame *)); void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object)); static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object)); +static void x_set_wait_for_wm P_ ((struct frame *, Lisp_Object, Lisp_Object)); void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object)); void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object)); void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object)); @@ -814,7 +801,8 @@ static struct x_frame_parm_table x_frame_parms[] = "scroll-bar-foreground", x_set_scroll_bar_foreground, "scroll-bar-background", x_set_scroll_bar_background, "screen-gamma", x_set_screen_gamma, - "line-spacing", x_set_line_spacing + "line-spacing", x_set_line_spacing, + "wait-for-wm", x_set_wait_for_wm }; /* Attach the `x-frame-parameter' properties to @@ -1280,7 +1268,7 @@ x_decode_color (f, color_name, mono_color) { XColor cdef; - CHECK_STRING (color_name, 0); + CHECK_STRING (color_name); #if 0 /* Don't do this. It's wrong when we're not using the default colormap, it makes freeing difficult, and it's probably not @@ -1327,8 +1315,22 @@ x_set_line_spacing (f, new_value, old_value) } +/* Change the `wait-for-wm' frame parameter of frame F. OLD_VALUE is + the previous value of that parameter, NEW_VALUE is the new value. + See also the comment of wait_for_wm in struct x_output. */ + +static void +x_set_wait_for_wm (f, new_value, old_value) + struct frame *f; + Lisp_Object new_value, old_value; +{ + f->output_data.x->wait_for_wm = !NILP (new_value); +} + + /* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is - the previous value of that parameter, NEW_VALUE is the new value. */ + the previous value of that parameter, NEW_VALUE is the new + value. */ static void x_set_screen_gamma (f, new_value, old_value) @@ -1361,24 +1363,37 @@ x_set_foreground_color (f, arg, oldval) struct frame *f; Lisp_Object arg, oldval; { - unsigned long pixel - = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); + struct x_output *x = f->output_data.x; + unsigned long fg, old_fg; - unload_color (f, f->output_data.x->foreground_pixel); - f->output_data.x->foreground_pixel = pixel; + fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); + old_fg = x->foreground_pixel; + x->foreground_pixel = fg; if (FRAME_X_WINDOW (f) != 0) { + Display *dpy = FRAME_X_DISPLAY (f); + BLOCK_INPUT; - XSetForeground (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc, - f->output_data.x->foreground_pixel); - XSetBackground (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc, - f->output_data.x->foreground_pixel); + XSetForeground (dpy, x->normal_gc, fg); + XSetBackground (dpy, x->reverse_gc, fg); + + if (x->cursor_pixel == old_fg) + { + unload_color (f, x->cursor_pixel); + x->cursor_pixel = x_copy_color (f, fg); + XSetBackground (dpy, x->cursor_gc, x->cursor_pixel); + } + UNBLOCK_INPUT; + update_face_from_frame_parameter (f, Qforeground_color, arg); + if (FRAME_VISIBLE_P (f)) redraw_frame (f); } + + unload_color (f, old_fg); } void @@ -1386,34 +1401,38 @@ x_set_background_color (f, arg, oldval) struct frame *f; Lisp_Object arg, oldval; { - unsigned long pixel - = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f)); + struct x_output *x = f->output_data.x; + unsigned long bg; - unload_color (f, f->output_data.x->background_pixel); - f->output_data.x->background_pixel = pixel; + bg = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f)); + unload_color (f, x->background_pixel); + x->background_pixel = bg; if (FRAME_X_WINDOW (f) != 0) { + Display *dpy = FRAME_X_DISPLAY (f); + BLOCK_INPUT; - /* The main frame area. */ - XSetBackground (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc, - f->output_data.x->background_pixel); - XSetForeground (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc, - f->output_data.x->background_pixel); - XSetForeground (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc, - f->output_data.x->background_pixel); - XSetWindowBackground (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - f->output_data.x->background_pixel); + XSetBackground (dpy, x->normal_gc, bg); + XSetForeground (dpy, x->reverse_gc, bg); + XSetWindowBackground (dpy, FRAME_X_WINDOW (f), bg); + XSetForeground (dpy, x->cursor_gc, bg); + +#ifndef USE_TOOLKIT_SCROLL_BARS /* Turns out to be annoying with + toolkit scroll bars. */ { Lisp_Object bar; - for (bar = FRAME_SCROLL_BARS (f); !NILP (bar); + for (bar = FRAME_SCROLL_BARS (f); + !NILP (bar); bar = XSCROLL_BAR (bar)->next) - XSetWindowBackground (FRAME_X_DISPLAY (f), - SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)), - f->output_data.x->background_pixel); + { + Window window = SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)); + XSetWindowBackground (dpy, window, bg); + } } - UNBLOCK_INPUT; +#endif /* USE_TOOLKIT_SCROLL_BARS */ + UNBLOCK_INPUT; update_face_from_frame_parameter (f, Qbackground_color, arg); if (FRAME_VISIBLE_P (f)) @@ -1426,127 +1445,141 @@ x_set_mouse_color (f, arg, oldval) struct frame *f; Lisp_Object arg, oldval; { + struct x_output *x = f->output_data.x; + Display *dpy = FRAME_X_DISPLAY (f); Cursor cursor, nontext_cursor, mode_cursor, cross_cursor; - Cursor busy_cursor; + Cursor hourglass_cursor, horizontal_drag_cursor; int count; unsigned long pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); - unsigned long mask_color = f->output_data.x->background_pixel; + unsigned long mask_color = x->background_pixel; /* Don't let pointers be invisible. */ - if (mask_color == pixel - && mask_color == f->output_data.x->background_pixel) - pixel = f->output_data.x->foreground_pixel; + if (mask_color == pixel) + { + x_free_colors (f, &pixel, 1); + pixel = x_copy_color (f, x->foreground_pixel); + } - unload_color (f, f->output_data.x->mouse_pixel); - f->output_data.x->mouse_pixel = pixel; + unload_color (f, x->mouse_pixel); + x->mouse_pixel = pixel; BLOCK_INPUT; /* It's not okay to crash if the user selects a screwy cursor. */ - count = x_catch_errors (FRAME_X_DISPLAY (f)); + count = x_catch_errors (dpy); - if (!EQ (Qnil, Vx_pointer_shape)) + if (!NILP (Vx_pointer_shape)) { - CHECK_NUMBER (Vx_pointer_shape, 0); - cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), XINT (Vx_pointer_shape)); + CHECK_NUMBER (Vx_pointer_shape); + cursor = XCreateFontCursor (dpy, XINT (Vx_pointer_shape)); } else - cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_xterm); - x_check_errors (FRAME_X_DISPLAY (f), "bad text pointer cursor: %s"); + cursor = XCreateFontCursor (dpy, XC_xterm); + x_check_errors (dpy, "bad text pointer cursor: %s"); - if (!EQ (Qnil, Vx_nontext_pointer_shape)) + if (!NILP (Vx_nontext_pointer_shape)) { - CHECK_NUMBER (Vx_nontext_pointer_shape, 0); - nontext_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), - XINT (Vx_nontext_pointer_shape)); + CHECK_NUMBER (Vx_nontext_pointer_shape); + nontext_cursor + = XCreateFontCursor (dpy, XINT (Vx_nontext_pointer_shape)); } else - nontext_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_left_ptr); - x_check_errors (FRAME_X_DISPLAY (f), "bad nontext pointer cursor: %s"); + nontext_cursor = XCreateFontCursor (dpy, XC_left_ptr); + x_check_errors (dpy, "bad nontext pointer cursor: %s"); - if (!EQ (Qnil, Vx_busy_pointer_shape)) + if (!NILP (Vx_hourglass_pointer_shape)) { - CHECK_NUMBER (Vx_busy_pointer_shape, 0); - busy_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), - XINT (Vx_busy_pointer_shape)); + CHECK_NUMBER (Vx_hourglass_pointer_shape); + hourglass_cursor + = XCreateFontCursor (dpy, XINT (Vx_hourglass_pointer_shape)); } else - busy_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_watch); - x_check_errors (FRAME_X_DISPLAY (f), "bad busy pointer cursor: %s"); + hourglass_cursor = XCreateFontCursor (dpy, XC_watch); + x_check_errors (dpy, "bad hourglass pointer cursor: %s"); - x_check_errors (FRAME_X_DISPLAY (f), "bad nontext pointer cursor: %s"); - if (!EQ (Qnil, Vx_mode_pointer_shape)) + x_check_errors (dpy, "bad nontext pointer cursor: %s"); + if (!NILP (Vx_mode_pointer_shape)) { - CHECK_NUMBER (Vx_mode_pointer_shape, 0); - mode_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), - XINT (Vx_mode_pointer_shape)); + CHECK_NUMBER (Vx_mode_pointer_shape); + mode_cursor = XCreateFontCursor (dpy, XINT (Vx_mode_pointer_shape)); } else - mode_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_xterm); - x_check_errors (FRAME_X_DISPLAY (f), "bad modeline pointer cursor: %s"); + mode_cursor = XCreateFontCursor (dpy, XC_xterm); + x_check_errors (dpy, "bad modeline pointer cursor: %s"); - if (!EQ (Qnil, Vx_sensitive_text_pointer_shape)) + if (!NILP (Vx_sensitive_text_pointer_shape)) { - CHECK_NUMBER (Vx_sensitive_text_pointer_shape, 0); + CHECK_NUMBER (Vx_sensitive_text_pointer_shape); cross_cursor - = XCreateFontCursor (FRAME_X_DISPLAY (f), - XINT (Vx_sensitive_text_pointer_shape)); + = XCreateFontCursor (dpy, XINT (Vx_sensitive_text_pointer_shape)); + } + else + cross_cursor = XCreateFontCursor (dpy, XC_crosshair); + + if (!NILP (Vx_window_horizontal_drag_shape)) + { + CHECK_NUMBER (Vx_window_horizontal_drag_shape); + horizontal_drag_cursor + = XCreateFontCursor (dpy, XINT (Vx_window_horizontal_drag_shape)); } else - cross_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_crosshair); + horizontal_drag_cursor + = XCreateFontCursor (dpy, XC_sb_h_double_arrow); /* Check and report errors with the above calls. */ - x_check_errors (FRAME_X_DISPLAY (f), "can't set cursor shape: %s"); - x_uncatch_errors (FRAME_X_DISPLAY (f), count); + x_check_errors (dpy, "can't set cursor shape: %s"); + x_uncatch_errors (dpy, count); { XColor fore_color, back_color; - fore_color.pixel = f->output_data.x->mouse_pixel; + fore_color.pixel = x->mouse_pixel; x_query_color (f, &fore_color); back_color.pixel = mask_color; x_query_color (f, &back_color); - XRecolorCursor (FRAME_X_DISPLAY (f), cursor, - &fore_color, &back_color); - XRecolorCursor (FRAME_X_DISPLAY (f), nontext_cursor, - &fore_color, &back_color); - XRecolorCursor (FRAME_X_DISPLAY (f), mode_cursor, - &fore_color, &back_color); - XRecolorCursor (FRAME_X_DISPLAY (f), cross_cursor, - &fore_color, &back_color); - XRecolorCursor (FRAME_X_DISPLAY (f), busy_cursor, - &fore_color, &back_color); + XRecolorCursor (dpy, cursor, &fore_color, &back_color); + XRecolorCursor (dpy, nontext_cursor, &fore_color, &back_color); + XRecolorCursor (dpy, mode_cursor, &fore_color, &back_color); + XRecolorCursor (dpy, cross_cursor, &fore_color, &back_color); + XRecolorCursor (dpy, hourglass_cursor, &fore_color, &back_color); + XRecolorCursor (dpy, horizontal_drag_cursor, &fore_color, &back_color); } if (FRAME_X_WINDOW (f) != 0) - XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor); - - if (cursor != f->output_data.x->text_cursor && f->output_data.x->text_cursor != 0) - XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->text_cursor); - f->output_data.x->text_cursor = cursor; - - if (nontext_cursor != f->output_data.x->nontext_cursor - && f->output_data.x->nontext_cursor != 0) - XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->nontext_cursor); - f->output_data.x->nontext_cursor = nontext_cursor; - - if (busy_cursor != f->output_data.x->busy_cursor - && f->output_data.x->busy_cursor != 0) - XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->busy_cursor); - f->output_data.x->busy_cursor = busy_cursor; - - if (mode_cursor != f->output_data.x->modeline_cursor - && f->output_data.x->modeline_cursor != 0) - XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->modeline_cursor); - f->output_data.x->modeline_cursor = mode_cursor; + XDefineCursor (dpy, FRAME_X_WINDOW (f), cursor); + + if (cursor != x->text_cursor + && x->text_cursor != 0) + XFreeCursor (dpy, x->text_cursor); + x->text_cursor = cursor; + + if (nontext_cursor != x->nontext_cursor + && x->nontext_cursor != 0) + XFreeCursor (dpy, x->nontext_cursor); + x->nontext_cursor = nontext_cursor; + + if (hourglass_cursor != x->hourglass_cursor + && x->hourglass_cursor != 0) + XFreeCursor (dpy, x->hourglass_cursor); + x->hourglass_cursor = hourglass_cursor; + + if (mode_cursor != x->modeline_cursor + && x->modeline_cursor != 0) + XFreeCursor (dpy, f->output_data.x->modeline_cursor); + x->modeline_cursor = mode_cursor; - if (cross_cursor != f->output_data.x->cross_cursor - && f->output_data.x->cross_cursor != 0) - XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->cross_cursor); - f->output_data.x->cross_cursor = cross_cursor; + if (cross_cursor != x->cross_cursor + && x->cross_cursor != 0) + XFreeCursor (dpy, x->cross_cursor); + x->cross_cursor = cross_cursor; - XFlush (FRAME_X_DISPLAY (f)); + if (horizontal_drag_cursor != x->horizontal_drag_cursor + && x->horizontal_drag_cursor != 0) + XFreeCursor (dpy, x->horizontal_drag_cursor); + x->horizontal_drag_cursor = horizontal_drag_cursor; + + XFlush (dpy); UNBLOCK_INPUT; update_face_from_frame_parameter (f, Qmouse_color, arg); @@ -1559,6 +1592,7 @@ x_set_cursor_color (f, arg, oldval) { unsigned long fore_pixel, pixel; int fore_pixel_allocated_p = 0, pixel_allocated_p = 0; + struct x_output *x = f->output_data.x; if (!NILP (Vx_cursor_fore_pixel)) { @@ -1567,13 +1601,13 @@ x_set_cursor_color (f, arg, oldval) fore_pixel_allocated_p = 1; } else - fore_pixel = f->output_data.x->background_pixel; + fore_pixel = x->background_pixel; pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); pixel_allocated_p = 1; /* Make sure that the cursor color differs from the background color. */ - if (pixel == f->output_data.x->background_pixel) + if (pixel == x->background_pixel) { if (pixel_allocated_p) { @@ -1581,7 +1615,7 @@ x_set_cursor_color (f, arg, oldval) pixel_allocated_p = 0; } - pixel = f->output_data.x->mouse_pixel; + pixel = x->mouse_pixel; if (pixel == fore_pixel) { if (fore_pixel_allocated_p) @@ -1589,27 +1623,25 @@ x_set_cursor_color (f, arg, oldval) x_free_colors (f, &fore_pixel, 1); fore_pixel_allocated_p = 0; } - fore_pixel = f->output_data.x->background_pixel; + fore_pixel = x->background_pixel; } } - unload_color (f, f->output_data.x->cursor_foreground_pixel); + unload_color (f, x->cursor_foreground_pixel); if (!fore_pixel_allocated_p) fore_pixel = x_copy_color (f, fore_pixel); - f->output_data.x->cursor_foreground_pixel = fore_pixel; + x->cursor_foreground_pixel = fore_pixel; - unload_color (f, f->output_data.x->cursor_pixel); + unload_color (f, x->cursor_pixel); if (!pixel_allocated_p) pixel = x_copy_color (f, pixel); - f->output_data.x->cursor_pixel = pixel; + x->cursor_pixel = pixel; if (FRAME_X_WINDOW (f) != 0) { BLOCK_INPUT; - XSetBackground (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc, - f->output_data.x->cursor_pixel); - XSetForeground (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc, - fore_pixel); + XSetBackground (FRAME_X_DISPLAY (f), x->cursor_gc, x->cursor_pixel); + XSetForeground (FRAME_X_DISPLAY (f), x->cursor_gc, fore_pixel); UNBLOCK_INPUT; if (FRAME_VISIBLE_P (f)) @@ -1640,7 +1672,7 @@ x_set_border_color (f, arg, oldval) { int pix; - CHECK_STRING (arg, 0); + CHECK_STRING (arg); pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); x_set_border_pixel (f, pix); update_face_from_frame_parameter (f, Qborder_color, arg); @@ -1817,8 +1849,9 @@ x_set_font (f, arg, oldval) Lisp_Object result; Lisp_Object fontset_name; Lisp_Object frame; + int old_fontset = f->output_data.x->fontset; - CHECK_STRING (arg, 1); + CHECK_STRING (arg); fontset_name = Fquery_fontset (arg, Qnil); @@ -1834,6 +1867,16 @@ x_set_font (f, arg, oldval) error ("The characters of the given font have varying widths"); else if (STRINGP (result)) { + if (STRINGP (fontset_name)) + { + /* Fontset names are built from ASCII font names, so the + names may be equal despite there was a change. */ + if (old_fontset == f->output_data.x->fontset) + return; + } + else if (!NILP (Fequal (result, oldval))) + return; + store_frame_param (f, Qfont, result); recompute_basic_faces (f); } @@ -1859,7 +1902,7 @@ x_set_border_width (f, arg, oldval) struct frame *f; Lisp_Object arg, oldval; { - CHECK_NUMBER (arg, 0); + CHECK_NUMBER (arg); if (XINT (arg) == f->output_data.x->border_width) return; @@ -1877,7 +1920,7 @@ x_set_internal_border_width (f, arg, oldval) { int old = f->output_data.x->internal_border_width; - CHECK_NUMBER (arg, 0); + CHECK_NUMBER (arg); f->output_data.x->internal_border_width = XINT (arg); if (f->output_data.x->internal_border_width < 0) f->output_data.x->internal_border_width = 0; @@ -1896,6 +1939,8 @@ x_set_internal_border_width (f, arg, oldval) SET_FRAME_GARBAGED (f); do_pending_window_change (0); } + else + SET_FRAME_GARBAGED (f); } void @@ -2008,6 +2053,10 @@ x_set_tool_bar_lines (f, value, oldval) int delta, nlines, root_height; Lisp_Object root_window; + /* Treat tool bars like menu bars. */ + if (FRAME_MINIBUF_ONLY_P (f)) + return; + /* Use VALUE only if an integer >= 0. */ if (INTEGERP (value) && XINT (value) >= 0) nlines = XFASTINT (value); @@ -2056,9 +2105,12 @@ x_set_tool_bar_lines (f, value, oldval) int y = nlines * CANON_Y_UNIT (f); BLOCK_INPUT; - XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - 0, y, width, height, False); + x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + 0, y, width, height, False); UNBLOCK_INPUT; + + if (WINDOWP (f->tool_bar_window)) + clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix); } } @@ -2118,6 +2170,20 @@ x_set_scroll_bar_background (f, value, oldval) if (f->output_data.x->scroll_bar_background_pixel != -1) unload_color (f, f->output_data.x->scroll_bar_background_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); + f->output_data.x->scroll_bar_top_shadow_pixel = -1; + } + if (f->output_data.x->scroll_bar_bottom_shadow_pixel != -1) + { + unload_color (f, f->output_data.x->scroll_bar_bottom_shadow_pixel); + f->output_data.x->scroll_bar_bottom_shadow_pixel = -1; + } +#endif /* USE_TOOLKIT_SCROLL_BARS */ + f->output_data.x->scroll_bar_background_pixel = pixel; if (FRAME_X_WINDOW (f) && FRAME_VISIBLE_P (f)) { @@ -2229,7 +2295,7 @@ x_set_name (f, name, explicit) name = build_string (FRAME_X_DISPLAY_INFO (f)->x_id_name); } else - CHECK_STRING (name, 0); + CHECK_STRING (name); /* Don't change the name if it's already NAME. */ if (! NILP (Fstring_equal (name, f->name))) @@ -2347,7 +2413,7 @@ x_set_title (f, name, old_name) if (NILP (name)) name = f->name; else - CHECK_STRING (name, 0); + CHECK_STRING (name); if (FRAME_X_WINDOW (f)) { @@ -2579,16 +2645,16 @@ validate_x_resource_name () extern char *x_get_string_resource (); DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0, - "Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.\n\ -This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the\n\ -class, where INSTANCE is the name under which Emacs was invoked, or\n\ -the name specified by the `-name' or `-rn' command-line arguments.\n\ -\n\ -The optional arguments COMPONENT and SUBCLASS add to the key and the\n\ -class, respectively. You must specify both of them or neither.\n\ -If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'\n\ -and the class is `Emacs.CLASS.SUBCLASS'.") - (attribute, class, component, subclass) + doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database. +This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the +class, where INSTANCE is the name under which Emacs was invoked, or +the name specified by the `-name' or `-rn' command-line arguments. + +The optional arguments COMPONENT and SUBCLASS add to the key and the +class, respectively. You must specify both of them or neither. +If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE' +and the class is `Emacs.CLASS.SUBCLASS'. */) + (attribute, class, component, subclass) Lisp_Object attribute, class, component, subclass; { register char *value; @@ -2597,13 +2663,13 @@ and the class is `Emacs.CLASS.SUBCLASS'.") check_x (); - CHECK_STRING (attribute, 0); - CHECK_STRING (class, 0); + CHECK_STRING (attribute); + CHECK_STRING (class); if (!NILP (component)) - CHECK_STRING (component, 1); + CHECK_STRING (component); if (!NILP (subclass)) - CHECK_STRING (subclass, 2); + CHECK_STRING (subclass); if (NILP (component) != NILP (subclass)) error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither"); @@ -2663,13 +2729,13 @@ display_x_get_resource (dpyinfo, attribute, class, component, subclass) char *name_key; char *class_key; - CHECK_STRING (attribute, 0); - CHECK_STRING (class, 0); + CHECK_STRING (attribute); + CHECK_STRING (class); if (!NILP (component)) - CHECK_STRING (component, 1); + CHECK_STRING (component); if (!NILP (subclass)) - CHECK_STRING (subclass, 2); + CHECK_STRING (subclass); if (NILP (component) != NILP (subclass)) error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither"); @@ -2910,9 +2976,9 @@ x_default_scroll_bar_color_parameter (f, alist, prop, xprop, xclass, build_string (foreground_p ? "foreground" : "background"), - build_string (""), + empty_string, build_string ("verticalScrollBar"), - build_string ("")); + empty_string); if (!STRINGP (tem)) { /* If nothing has been specified, scroll bars will use a @@ -2937,12 +3003,12 @@ x_default_scroll_bar_color_parameter (f, alist, prop, xprop, xclass, DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0, - "Parse an X-style geometry string STRING.\n\ -Returns an alist of the form ((top . TOP), (left . LEFT) ... ).\n\ -The properties returned may include `top', `left', `height', and `width'.\n\ -The value of `left' or `top' may be an integer,\n\ -or a list (+ N) meaning N pixels relative to top/left corner,\n\ -or a list (- N) meaning -N pixels relative to bottom/right corner.") + doc: /* Parse an X-style geometry string STRING. +Returns an alist of the form ((top . TOP), (left . LEFT) ... ). +The properties returned may include `top', `left', `height', and `width'. +The value of `left' or `top' may be an integer, +or a list (+ N) meaning N pixels relative to top/left corner, +or a list (- N) meaning -N pixels relative to bottom/right corner. */) (string) Lisp_Object string; { @@ -2950,7 +3016,7 @@ or a list (- N) meaning -N pixels relative to bottom/right corner.") unsigned int width, height; Lisp_Object result; - CHECK_STRING (string, 0); + CHECK_STRING (string); geometry = XParseGeometry ((char *) XSTRING (string)->data, &x, &y, &width, &height); @@ -3029,12 +3095,12 @@ x_figure_window_size (f, parms) { if (!EQ (tem0, Qunbound)) { - CHECK_NUMBER (tem0, 0); + CHECK_NUMBER (tem0); f->height = XINT (tem0); } if (!EQ (tem1, Qunbound)) { - CHECK_NUMBER (tem1, 0); + CHECK_NUMBER (tem1); SET_FRAME_WIDTH (f, XINT (tem1)); } if (!NILP (tem2) && !EQ (tem2, Qunbound)) @@ -3079,7 +3145,7 @@ x_figure_window_size (f, parms) f->output_data.x->top_pos = 0; else { - CHECK_NUMBER (tem0, 0); + CHECK_NUMBER (tem0); f->output_data.x->top_pos = XINT (tem0); if (f->output_data.x->top_pos < 0) window_prompting |= YNegative; @@ -3107,7 +3173,7 @@ x_figure_window_size (f, parms) f->output_data.x->left_pos = 0; else { - CHECK_NUMBER (tem1, 0); + CHECK_NUMBER (tem1); f->output_data.x->left_pos = XINT (tem1); if (f->output_data.x->left_pos < 0) window_prompting |= XNegative; @@ -3275,6 +3341,8 @@ best_xim_style (user, xim) /* Create XIC for frame F. */ +static XIMStyle xic_style; + void create_frame_xic (f) struct frame *f; @@ -3282,7 +3350,6 @@ create_frame_xic (f) XIM xim; XIC xic = NULL; XFontSet xfs = NULL; - static XIMStyle xic_style; if (FRAME_XIC (f)) return; @@ -3859,8 +3926,8 @@ x_icon (f, parms) icon_y = x_get_and_record_arg (f, parms, Qicon_top, 0, 0, RES_TYPE_NUMBER); if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound)) { - CHECK_NUMBER (icon_x, 0); - CHECK_NUMBER (icon_y, 0); + CHECK_NUMBER (icon_x); + CHECK_NUMBER (icon_y); } else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound)) error ("Both left and top icon corners of icon must be specified"); @@ -3912,20 +3979,20 @@ x_make_gc (f) gc_values.foreground = f->output_data.x->foreground_pixel; gc_values.background = f->output_data.x->background_pixel; gc_values.line_width = 0; /* Means 1 using fast algorithm. */ - f->output_data.x->normal_gc = XCreateGC (FRAME_X_DISPLAY (f), - FRAME_X_WINDOW (f), - GCLineWidth | GCFont - | GCForeground | GCBackground, - &gc_values); + f->output_data.x->normal_gc + = XCreateGC (FRAME_X_DISPLAY (f), + FRAME_X_WINDOW (f), + GCLineWidth | GCFont | GCForeground | GCBackground, + &gc_values); /* Reverse video style. */ gc_values.foreground = f->output_data.x->background_pixel; gc_values.background = f->output_data.x->foreground_pixel; - f->output_data.x->reverse_gc = XCreateGC (FRAME_X_DISPLAY (f), - FRAME_X_WINDOW (f), - GCFont | GCForeground | GCBackground - | GCLineWidth, - &gc_values); + f->output_data.x->reverse_gc + = XCreateGC (FRAME_X_DISPLAY (f), + FRAME_X_WINDOW (f), + GCFont | GCForeground | GCBackground | GCLineWidth, + &gc_values); /* Cursor has cursor-color background, background-color foreground. */ gc_values.foreground = f->output_data.x->background_pixel; @@ -3954,24 +4021,91 @@ x_make_gc (f) gray_bits, gray_width, gray_height, f->output_data.x->foreground_pixel, f->output_data.x->background_pixel, - DefaultDepth (FRAME_X_DISPLAY (f), - XScreenNumberOfScreen (FRAME_X_SCREEN (f))))); + DefaultDepth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f)))); + + UNBLOCK_INPUT; +} + + +/* Free what was was allocated in x_make_gc. */ + +void +x_free_gcs (f) + struct frame *f; +{ + Display *dpy = FRAME_X_DISPLAY (f); + + BLOCK_INPUT; + + if (f->output_data.x->normal_gc) + { + XFreeGC (dpy, f->output_data.x->normal_gc); + f->output_data.x->normal_gc = 0; + } + + if (f->output_data.x->reverse_gc) + { + XFreeGC (dpy, f->output_data.x->reverse_gc); + f->output_data.x->reverse_gc = 0; + } + + if (f->output_data.x->cursor_gc) + { + XFreeGC (dpy, f->output_data.x->cursor_gc); + f->output_data.x->cursor_gc = 0; + } + + if (f->output_data.x->border_tile) + { + XFreePixmap (dpy, f->output_data.x->border_tile); + f->output_data.x->border_tile = 0; + } UNBLOCK_INPUT; } + +/* Handler for signals raised during x_create_frame and + x_create_top_frame. FRAME is the frame which is partially + constructed. */ + +static Lisp_Object +unwind_create_frame (frame) + Lisp_Object frame; +{ + struct frame *f = XFRAME (frame); + + /* If frame is ``official'', nothing to do. */ + if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame)) + { +#if GLYPH_DEBUG + struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); +#endif + + x_free_frame_resources (f); + + /* Check that reference counts are indeed correct. */ + xassert (dpyinfo->reference_count == dpyinfo_refcount); + xassert (dpyinfo->image_cache->refcount == image_cache_refcount); + return Qt; + } + + return Qnil; +} + + DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame, 1, 1, 0, - "Make a new X window, which is called a \"frame\" in Emacs terms.\n\ -Returns an Emacs frame object.\n\ -ALIST is an alist of frame parameters.\n\ -If the parameters specify that the frame should not have a minibuffer,\n\ -and do not specify a specific minibuffer window to use,\n\ -then `default-minibuffer-frame' must be a frame whose minibuffer can\n\ -be shared by the new frame.\n\ -\n\ -This function is an internal primitive--use `make-frame' instead.") - (parms) + doc: /* Make a new X window, which is called a "frame" in Emacs terms. +Returns an Emacs frame object. +ALIST is an alist of frame parameters. +If the parameters specify that the frame should not have a minibuffer, +and do not specify a specific minibuffer window to use, +then `default-minibuffer-frame' must be a frame whose minibuffer can +be shared by the new frame. + +This function is an internal primitive--use `make-frame' instead. */) + (parms) Lisp_Object parms; { struct frame *f; @@ -3980,7 +4114,7 @@ This function is an internal primitive--use `make-frame' instead.") int minibuffer_only = 0; long window_prompting = 0; int width, height; - int count = specpdl_ptr - specpdl; + int count = BINDING_STACK_SIZE (); struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; Lisp_Object display; struct x_display_info *dpyinfo = NULL; @@ -4017,7 +4151,7 @@ This function is an internal primitive--use `make-frame' instead.") if (EQ (parent, Qunbound)) parent = Qnil; if (! NILP (parent)) - CHECK_NUMBER (parent, 0); + CHECK_NUMBER (parent); /* make_frame_without_minibuffer can run Lisp code and garbage collect. */ /* No need to protect DISPLAY because that's not used after passing @@ -4050,6 +4184,11 @@ This function is an internal primitive--use `make-frame' instead.") f->output_data.x->fontset = -1; f->output_data.x->scroll_bar_foreground_pixel = -1; f->output_data.x->scroll_bar_background_pixel = -1; +#ifdef USE_TOOLKIT_SCROLL_BARS + f->output_data.x->scroll_bar_top_shadow_pixel = -1; + f->output_data.x->scroll_bar_bottom_shadow_pixel = -1; +#endif /* USE_TOOLKIT_SCROLL_BARS */ + record_unwind_protect (unwind_create_frame, frame); f->icon_name = x_get_arg (dpyinfo, parms, Qicon_name, "iconName", "Title", @@ -4058,6 +4197,10 @@ This function is an internal primitive--use `make-frame' instead.") f->icon_name = Qnil; FRAME_X_DISPLAY_INFO (f) = dpyinfo; +#if GLYPH_DEBUG + image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount; + dpyinfo_refcount = dpyinfo->reference_count; +#endif /* GLYPH_DEBUG */ #ifdef MULTI_KBOARD FRAME_KBOARD (f) = kb; #endif @@ -4067,6 +4210,16 @@ This function is an internal primitive--use `make-frame' instead.") { Lisp_Object black; struct gcpro gcpro1; + + /* Function x_decode_color can signal an error. Make + sure to initialize color slots so that we won't try + to free colors we haven't allocated. */ + f->output_data.x->foreground_pixel = -1; + f->output_data.x->background_pixel = -1; + f->output_data.x->cursor_pixel = -1; + f->output_data.x->cursor_foreground_pixel = -1; + f->output_data.x->border_pixel = -1; + f->output_data.x->mouse_pixel = -1; black = build_string ("black"); GCPRO1 (black); @@ -4162,7 +4315,7 @@ This function is an internal primitive--use `make-frame' instead.") x_default_parameter (f, parms, Qborder_width, make_number (2), "borderWidth", "BorderWidth", RES_TYPE_NUMBER); - /* This defaults to 2 in order to match xterm. We recognize either + /* This defaults to 1 in order to match xterm. We recognize either internalBorderWidth or internalBorder (which is what xterm calls it). */ if (NILP (Fassq (Qinternal_border_width, parms))) @@ -4222,8 +4375,40 @@ This function is an internal primitive--use `make-frame' instead.") RES_TYPE_SYMBOL); x_default_parameter (f, parms, Qtitle, Qnil, "title", "Title", RES_TYPE_STRING); + x_default_parameter (f, parms, Qwait_for_wm, Qt, + "waitForWM", "WaitForWM", RES_TYPE_BOOLEAN); f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window; + + /* Add the tool-bar height to the initial frame height so that the + user gets a text display area of the size he specified with -g or + via .Xdefaults. Later changes of the tool-bar height don't + change the frame size. This is done so that users can create + tall Emacs frames without having to guess how tall the tool-bar + will get. */ + if (FRAME_TOOL_BAR_LINES (f)) + { + int margin, relief, bar_height; + + relief = (tool_bar_button_relief > 0 + ? tool_bar_button_relief + : DEFAULT_TOOL_BAR_BUTTON_RELIEF); + + if (INTEGERP (Vtool_bar_button_margin) + && XINT (Vtool_bar_button_margin) > 0) + margin = XFASTINT (Vtool_bar_button_margin); + else if (CONSP (Vtool_bar_button_margin) + && INTEGERP (XCDR (Vtool_bar_button_margin)) + && XINT (XCDR (Vtool_bar_button_margin)) > 0) + margin = XFASTINT (XCDR (Vtool_bar_button_margin)); + else + margin = 0; + + bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief; + f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f); + } + + /* Compute the size of the X window. */ window_prompting = x_figure_window_size (f, parms); if (window_prompting & XNegative) @@ -4246,14 +4431,7 @@ This function is an internal primitive--use `make-frame' instead.") tem = x_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN); f->no_split = minibuffer_only || EQ (tem, Qt); - /* Create the X widget or window. Add the tool-bar height to the - initial frame height so that the user gets a text display area of - the size he specified with -g or via .Xdefaults. Later changes - of the tool-bar height don't change the frame size. This is done - so that users can create tall Emacs frames without having to - guess how tall the tool-bar will get. */ - f->height += FRAME_TOOL_BAR_LINES (f); - + /* Create the X widget or window. */ #ifdef USE_X_TOOLKIT x_window (f, window_prompting, minibuffer_only); #else @@ -4287,10 +4465,18 @@ This function is an internal primitive--use `make-frame' instead.") f->height. */ width = f->width; height = f->height; + f->height = 0; SET_FRAME_WIDTH (f, 0); change_frame_size (f, height, width, 1, 0, 0); + /* Set up faces after all frame parameters are known. This call + also merges in face attributes specified for new frames. If we + don't do this, the `menu' face for instance won't have the right + colors, and the menu bar won't appear in the specified colors for + new frames. */ + call1 (Qface_set_after_frame_default, frame); + #ifdef USE_X_TOOLKIT /* Create the menu bar. */ if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f)) @@ -4336,9 +4522,15 @@ This function is an internal primitive--use `make-frame' instead.") } UNGCPRO; + + /* Make sure windows on this frame appear in calls to next-window + and similar functions. */ + Vwindow_list = Qnil; + return unbind_to (count, frame); } + /* FRAME is used only to get a handle on the X display. We don't pass the display info directly because we're called from frame.c, which doesn't know about that structure. */ @@ -4367,9 +4559,9 @@ x_get_focus_frame (frame) following a user-command. */ DEFUN ("x-focus-frame", Fx_focus_frame, Sx_focus_frame, 1, 1, 0, - "Set the input focus to FRAME.\n\ -FRAME nil means use the selected frame.") - (frame) + doc: /* Set the input focus to FRAME. +FRAME nil means use the selected frame. */) + (frame) Lisp_Object frame; { struct frame *f = check_x_frame (frame); @@ -4388,14 +4580,14 @@ FRAME nil means use the selected frame.") DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0, - "Internal function called by `color-defined-p', which see.") - (color, frame) + doc: /* Internal function called by `color-defined-p', which see. */) + (color, frame) Lisp_Object color, frame; { XColor foo; FRAME_PTR f = check_x_frame (frame); - CHECK_STRING (color, 1); + CHECK_STRING (color); if (x_defined_color (f, XSTRING (color)->data, &foo, 0)) return Qt; @@ -4404,14 +4596,14 @@ DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0, } DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0, - "Internal function called by `color-values', which see.") - (color, frame) + doc: /* Internal function called by `color-values', which see. */) + (color, frame) Lisp_Object color, frame; { XColor foo; FRAME_PTR f = check_x_frame (frame); - CHECK_STRING (color, 1); + CHECK_STRING (color); if (x_defined_color (f, XSTRING (color)->data, &foo, 0)) { @@ -4427,8 +4619,8 @@ DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0, } DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0, - "Internal function called by `display-color-p', which see.") - (display) + doc: /* Internal function called by `display-color-p', which see. */) + (display) Lisp_Object display; { struct x_display_info *dpyinfo = check_x_display_info (display); @@ -4450,13 +4642,13 @@ DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0, } DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p, - 0, 1, 0, - "Return t if the X display supports shades of gray.\n\ -Note that color displays do support shades of gray.\n\ -The optional argument DISPLAY specifies which display to ask about.\n\ -DISPLAY should be either a frame or a display name (a string).\n\ -If omitted or nil, that stands for the selected frame's display.") - (display) + 0, 1, 0, + doc: /* Return t if the X display supports shades of gray. +Note that color displays do support shades of gray. +The optional argument DISPLAY specifies which display to ask about. +DISPLAY should be either a frame or a display name (a string). +If omitted or nil, that stands for the selected frame's display. */) + (display) Lisp_Object display; { struct x_display_info *dpyinfo = check_x_display_info (display); @@ -4480,12 +4672,12 @@ If omitted or nil, that stands for the selected frame's display.") } DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width, - 0, 1, 0, - "Returns the width in pixels of the X display DISPLAY.\n\ -The optional argument DISPLAY specifies which display to ask about.\n\ -DISPLAY should be either a frame or a display name (a string).\n\ -If omitted or nil, that stands for the selected frame's display.") - (display) + 0, 1, 0, + doc: /* Returns the width in pixels of the X display DISPLAY. +The optional argument DISPLAY specifies which display to ask about. +DISPLAY should be either a frame or a display name (a string). +If omitted or nil, that stands for the selected frame's display. */) + (display) Lisp_Object display; { struct x_display_info *dpyinfo = check_x_display_info (display); @@ -4494,12 +4686,12 @@ If omitted or nil, that stands for the selected frame's display.") } DEFUN ("x-display-pixel-height", Fx_display_pixel_height, - Sx_display_pixel_height, 0, 1, 0, - "Returns the height in pixels of the X display DISPLAY.\n\ -The optional argument DISPLAY specifies which display to ask about.\n\ -DISPLAY should be either a frame or a display name (a string).\n\ -If omitted or nil, that stands for the selected frame's display.") - (display) + Sx_display_pixel_height, 0, 1, 0, + doc: /* Returns the height in pixels of the X display DISPLAY. +The optional argument DISPLAY specifies which display to ask about. +DISPLAY should be either a frame or a display name (a string). +If omitted or nil, that stands for the selected frame's display. */) + (display) Lisp_Object display; { struct x_display_info *dpyinfo = check_x_display_info (display); @@ -4508,12 +4700,12 @@ If omitted or nil, that stands for the selected frame's display.") } DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes, - 0, 1, 0, - "Returns the number of bitplanes of the X display DISPLAY.\n\ -The optional argument DISPLAY specifies which display to ask about.\n\ -DISPLAY should be either a frame or a display name (a string).\n\ -If omitted or nil, that stands for the selected frame's display.") - (display) + 0, 1, 0, + doc: /* Returns the number of bitplanes of the X display DISPLAY. +The optional argument DISPLAY specifies which display to ask about. +DISPLAY should be either a frame or a display name (a string). +If omitted or nil, that stands for the selected frame's display. */) + (display) Lisp_Object display; { struct x_display_info *dpyinfo = check_x_display_info (display); @@ -4522,12 +4714,12 @@ If omitted or nil, that stands for the selected frame's display.") } DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells, - 0, 1, 0, - "Returns the number of color cells of the X display DISPLAY.\n\ -The optional argument DISPLAY specifies which display to ask about.\n\ -DISPLAY should be either a frame or a display name (a string).\n\ -If omitted or nil, that stands for the selected frame's display.") - (display) + 0, 1, 0, + doc: /* Returns the number of color cells of the X display DISPLAY. +The optional argument DISPLAY specifies which display to ask about. +DISPLAY should be either a frame or a display name (a string). +If omitted or nil, that stands for the selected frame's display. */) + (display) Lisp_Object display; { struct x_display_info *dpyinfo = check_x_display_info (display); @@ -4538,12 +4730,12 @@ If omitted or nil, that stands for the selected frame's display.") DEFUN ("x-server-max-request-size", Fx_server_max_request_size, Sx_server_max_request_size, - 0, 1, 0, - "Returns the maximum request size of the X server of display DISPLAY.\n\ -The optional argument DISPLAY specifies which display to ask about.\n\ -DISPLAY should be either a frame or a display name (a string).\n\ -If omitted or nil, that stands for the selected frame's display.") - (display) + 0, 1, 0, + doc: /* Returns the maximum request size of the X server of display DISPLAY. +The optional argument DISPLAY specifies which display to ask about. +DISPLAY should be either a frame or a display name (a string). +If omitted or nil, that stands for the selected frame's display. */) + (display) Lisp_Object display; { struct x_display_info *dpyinfo = check_x_display_info (display); @@ -4552,11 +4744,11 @@ If omitted or nil, that stands for the selected frame's display.") } DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0, - "Returns the vendor ID string of the X server of display DISPLAY.\n\ -The optional argument DISPLAY specifies which display to ask about.\n\ -DISPLAY should be either a frame or a display name (a string).\n\ -If omitted or nil, that stands for the selected frame's display.") - (display) + doc: /* Returns the vendor ID string of the X server of display DISPLAY. +The optional argument DISPLAY specifies which display to ask about. +DISPLAY should be either a frame or a display name (a string). +If omitted or nil, that stands for the selected frame's display. */) + (display) Lisp_Object display; { struct x_display_info *dpyinfo = check_x_display_info (display); @@ -4567,14 +4759,15 @@ If omitted or nil, that stands for the selected frame's display.") } DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0, - "Returns the version numbers of the X server of display DISPLAY.\n\ -The value is a list of three integers: the major and minor\n\ -version numbers of the X Protocol in use, and the vendor-specific release\n\ -number. See also the function `x-server-vendor'.\n\n\ -The optional argument DISPLAY specifies which display to ask about.\n\ -DISPLAY should be either a frame or a display name (a string).\n\ -If omitted or nil, that stands for the selected frame's display.") - (display) + doc: /* Returns the version numbers of the X server of display DISPLAY. +The value is a list of three integers: the major and minor +version numbers of the X Protocol in use, and the vendor-specific release +number. See also the function `x-server-vendor'. + +The optional argument DISPLAY specifies which display to ask about. +DISPLAY should be either a frame or a display name (a string). +If omitted or nil, that stands for the selected frame's display. */) + (display) Lisp_Object display; { struct x_display_info *dpyinfo = check_x_display_info (display); @@ -4586,11 +4779,11 @@ If omitted or nil, that stands for the selected frame's display.") } DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0, - "Returns the number of screens on the X server of display DISPLAY.\n\ -The optional argument DISPLAY specifies which display to ask about.\n\ -DISPLAY should be either a frame or a display name (a string).\n\ -If omitted or nil, that stands for the selected frame's display.") - (display) + doc: /* Return the number of screens on the X server of display DISPLAY. +The optional argument DISPLAY specifies which display to ask about. +DISPLAY should be either a frame or a display name (a string). +If omitted or nil, that stands for the selected frame's display. */) + (display) Lisp_Object display; { struct x_display_info *dpyinfo = check_x_display_info (display); @@ -4599,11 +4792,11 @@ If omitted or nil, that stands for the selected frame's display.") } DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0, - "Returns the height in millimeters of the X display DISPLAY.\n\ -The optional argument DISPLAY specifies which display to ask about.\n\ -DISPLAY should be either a frame or a display name (a string).\n\ -If omitted or nil, that stands for the selected frame's display.") - (display) + doc: /* Return the height in millimeters of the X display DISPLAY. +The optional argument DISPLAY specifies which display to ask about. +DISPLAY should be either a frame or a display name (a string). +If omitted or nil, that stands for the selected frame's display. */) + (display) Lisp_Object display; { struct x_display_info *dpyinfo = check_x_display_info (display); @@ -4612,11 +4805,11 @@ If omitted or nil, that stands for the selected frame's display.") } DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0, - "Returns the width in millimeters of the X display DISPLAY.\n\ -The optional argument DISPLAY specifies which display to ask about.\n\ -DISPLAY should be either a frame or a display name (a string).\n\ -If omitted or nil, that stands for the selected frame's display.") - (display) + doc: /* Return the width in millimeters of the X display DISPLAY. +The optional argument DISPLAY specifies which display to ask about. +DISPLAY should be either a frame or a display name (a string). +If omitted or nil, that stands for the selected frame's display. */) + (display) Lisp_Object display; { struct x_display_info *dpyinfo = check_x_display_info (display); @@ -4625,13 +4818,13 @@ If omitted or nil, that stands for the selected frame's display.") } DEFUN ("x-display-backing-store", Fx_display_backing_store, - Sx_display_backing_store, 0, 1, 0, - "Returns an indication of whether X display DISPLAY does backing store.\n\ -The value may be `always', `when-mapped', or `not-useful'.\n\ -The optional argument DISPLAY specifies which display to ask about.\n\ -DISPLAY should be either a frame or a display name (a string).\n\ -If omitted or nil, that stands for the selected frame's display.") - (display) + Sx_display_backing_store, 0, 1, 0, + doc: /* Returns an indication of whether X display DISPLAY does backing store. +The value may be `always', `when-mapped', or `not-useful'. +The optional argument DISPLAY specifies which display to ask about. +DISPLAY should be either a frame or a display name (a string). +If omitted or nil, that stands for the selected frame's display. */) + (display) Lisp_Object display; { struct x_display_info *dpyinfo = check_x_display_info (display); @@ -4660,14 +4853,15 @@ If omitted or nil, that stands for the selected frame's display.") } DEFUN ("x-display-visual-class", Fx_display_visual_class, - Sx_display_visual_class, 0, 1, 0, - "Returns the visual class of the X display DISPLAY.\n\ -The value is one of the symbols `static-gray', `gray-scale',\n\ -`static-color', `pseudo-color', `true-color', or `direct-color'.\n\n\ -The optional argument DISPLAY specifies which display to ask about.\n\ -DISPLAY should be either a frame or a display name (a string).\n\ -If omitted or nil, that stands for the selected frame's display.") - (display) + Sx_display_visual_class, 0, 1, 0, + doc: /* Return the visual class of the X display DISPLAY. +The value is one of the symbols `static-gray', `gray-scale', +`static-color', `pseudo-color', `true-color', or `direct-color'. + +The optional argument DISPLAY specifies which display to ask about. +DISPLAY should be either a frame or a display name (a string). +If omitted or nil, that stands for the selected frame's display. */) + (display) Lisp_Object display; { struct x_display_info *dpyinfo = check_x_display_info (display); @@ -4702,12 +4896,12 @@ If omitted or nil, that stands for the selected frame's display.") } DEFUN ("x-display-save-under", Fx_display_save_under, - Sx_display_save_under, 0, 1, 0, - "Returns t if the X display DISPLAY supports the save-under feature.\n\ -The optional argument DISPLAY specifies which display to ask about.\n\ -DISPLAY should be either a frame or a display name (a string).\n\ -If omitted or nil, that stands for the selected frame's display.") - (display) + Sx_display_save_under, 0, 1, 0, + doc: /* Returns t if the X display DISPLAY supports the save-under feature. +The optional argument DISPLAY specifies which display to ask about. +DISPLAY should be either a frame or a display name (a string). +If omitted or nil, that stands for the selected frame's display. */) + (display) Lisp_Object display; { struct x_display_info *dpyinfo = check_x_display_info (display); @@ -4792,7 +4986,7 @@ XScreenNumberOfScreen (scr) int i; for (i = 0; i < dpy->nscreens; ++i) - if (scr == dpy->screens[i]) + if (scr == dpy->screens + i) break; return i; @@ -4889,7 +5083,7 @@ x_display_info_for_name (name) Lisp_Object names; struct x_display_info *dpyinfo; - CHECK_STRING (name, 0); + CHECK_STRING (name); if (! EQ (Vwindow_system, intern ("x"))) error ("Not using X Windows"); @@ -4909,7 +5103,7 @@ x_display_info_for_name (name) validate_x_resource_name (); - dpyinfo = x_term_init (name, (unsigned char *)0, + dpyinfo = x_term_init (name, (char *)0, (char *) XSTRING (Vx_resource_name)->data); if (dpyinfo == 0) @@ -4923,20 +5117,21 @@ x_display_info_for_name (name) DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection, - 1, 3, 0, "Open a connection to an X server.\n\ -DISPLAY is the name of the display to connect to.\n\ -Optional second arg XRM-STRING is a string of resources in xrdb format.\n\ -If the optional third arg MUST-SUCCEED is non-nil,\n\ -terminate Emacs if we can't open the connection.") - (display, xrm_string, must_succeed) + 1, 3, 0, + doc: /* Open a connection to an X server. +DISPLAY is the name of the display to connect to. +Optional second arg XRM-STRING is a string of resources in xrdb format. +If the optional third arg MUST-SUCCEED is non-nil, +terminate Emacs if we can't open the connection. */) + (display, xrm_string, must_succeed) Lisp_Object display, xrm_string, must_succeed; { unsigned char *xrm_option; struct x_display_info *dpyinfo; - CHECK_STRING (display, 0); + CHECK_STRING (display); if (! NILP (xrm_string)) - CHECK_STRING (xrm_string, 1); + CHECK_STRING (xrm_string); if (! EQ (Vwindow_system, intern ("x"))) error ("Not using X Windows"); @@ -4973,11 +5168,11 @@ connections from your machine.\n", DEFUN ("x-close-connection", Fx_close_connection, Sx_close_connection, 1, 1, 0, - "Close the connection to DISPLAY's X server.\n\ -For DISPLAY, specify either a frame or a display name (a string).\n\ -If DISPLAY is nil, that stands for the selected frame's display.") - (display) - Lisp_Object display; + doc: /* Close the connection to DISPLAY's X server. +For DISPLAY, specify either a frame or a display name (a string). +If DISPLAY is nil, that stands for the selected frame's display. */) + (display) + Lisp_Object display; { struct x_display_info *dpyinfo = check_x_display_info (display); int i; @@ -5012,8 +5207,8 @@ If DISPLAY is nil, that stands for the selected frame's display.") } DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0, - "Return the list of display names that Emacs has connections to.") - () + doc: /* Return the list of display names that Emacs has connections to. */) + () { Lisp_Object tail, result; @@ -5025,15 +5220,15 @@ DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0, } DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0, - "If ON is non-nil, report X errors as soon as the erring request is made.\n\ -If ON is nil, allow buffering of requests.\n\ -Turning on synchronization prohibits the Xlib routines from buffering\n\ -requests and seriously degrades performance, but makes debugging much\n\ -easier.\n\ -The optional second argument DISPLAY specifies which display to act on.\n\ -DISPLAY should be either a frame or a display name (a string).\n\ -If DISPLAY is omitted or nil, that stands for the selected frame's display.") - (on, display) + doc: /* If ON is non-nil, report X errors as soon as the erring request is made. +If ON is nil, allow buffering of requests. +Turning on synchronization prohibits the Xlib routines from buffering +requests and seriously degrades performance, but makes debugging much +easier. +The optional second argument DISPLAY specifies which display to act on. +DISPLAY should be either a frame or a display name (a string). +If DISPLAY is omitted or nil, that stands for the selected frame's display. */) + (on, display) Lisp_Object display, on; { struct x_display_info *dpyinfo = check_x_display_info (display); @@ -5082,7 +5277,7 @@ Lisp_Object Qxbm; extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile; extern Lisp_Object QCdata; Lisp_Object QCtype, QCascent, QCmargin, QCrelief; -Lisp_Object QCalgorithm, QCcolor_symbols, QCheuristic_mask; +Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask; Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask; /* Other symbols. */ @@ -5154,11 +5349,22 @@ valid_image_p (object) if (CONSP (object) && EQ (XCAR (object), Qimage)) { - Lisp_Object symbol = Fplist_get (XCDR (object), QCtype); - struct image_type *type = lookup_image_type (symbol); - - if (type) - valid_p = type->valid_p (object); + Lisp_Object tem; + + for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem)) + if (EQ (XCAR (tem), QCtype)) + { + tem = XCDR (tem); + if (CONSP (tem) && SYMBOLP (XCAR (tem))) + { + struct image_type *type; + type = lookup_image_type (XCAR (tem)); + if (type) + valid_p = type->valid_p (object); + } + + break; + } } return valid_p; @@ -5189,8 +5395,10 @@ enum image_value_type { IMAGE_DONT_CHECK_VALUE_TYPE, IMAGE_STRING_VALUE, + IMAGE_STRING_OR_NIL_VALUE, IMAGE_SYMBOL_VALUE, IMAGE_POSITIVE_INTEGER_VALUE, + IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, IMAGE_NON_NEGATIVE_INTEGER_VALUE, IMAGE_ASCENT_VALUE, IMAGE_INTEGER_VALUE, @@ -5285,6 +5493,11 @@ parse_image_spec (spec, keywords, nkeywords, type) return 0; break; + case IMAGE_STRING_OR_NIL_VALUE: + if (!STRINGP (value) && !NILP (value)) + return 0; + break; + case IMAGE_SYMBOL_VALUE: if (!SYMBOLP (value)) return 0; @@ -5295,6 +5508,15 @@ parse_image_spec (spec, keywords, nkeywords, type) return 0; break; + case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR: + if (INTEGERP (value) && XINT (value) >= 0) + break; + if (CONSP (value) + && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value)) + && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0) + break; + return 0; + case IMAGE_ASCENT_VALUE: if (SYMBOLP (value) && EQ (value, Qcenter)) break; @@ -5385,12 +5607,12 @@ image_spec_value (spec, key, found) DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0, - "Return the size of image SPEC as pair (WIDTH . HEIGHT).\n\ -PIXELS non-nil means return the size in pixels, otherwise return the\n\ -size in canonical character units.\n\ -FRAME is the frame on which the image will be displayed. FRAME nil\n\ -or omitted means use the selected frame.") - (spec, pixels, frame) + doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT). +PIXELS non-nil means return the size in pixels, otherwise return the +size in canonical character units. +FRAME is the frame on which the image will be displayed. FRAME nil +or omitted means use the selected frame. */) + (spec, pixels, frame) Lisp_Object spec, pixels, frame; { Lisp_Object size; @@ -5401,8 +5623,8 @@ or omitted means use the selected frame.") struct frame *f = check_x_frame (frame); int id = lookup_image (f, spec); struct image *img = IMAGE_FROM_ID (f, id); - int width = img->width + 2 * img->margin; - int height = img->height + 2 * img->margin; + int width = img->width + 2 * img->hmargin; + int height = img->height + 2 * img->vmargin; if (NILP (pixels)) size = Fcons (make_float ((double) width / CANON_X_UNIT (f)), @@ -5418,10 +5640,10 @@ or omitted means use the selected frame.") DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0, - "Return t if image SPEC has a mask bitmap.\n\ -FRAME is the frame on which the image will be displayed. FRAME nil\n\ -or omitted means use the selected frame.") - (spec, frame) + doc: /* Return t if image SPEC has a mask bitmap. +FRAME is the frame on which the image will be displayed. FRAME nil +or omitted means use the selected frame. */) + (spec, frame) Lisp_Object spec, frame; { Lisp_Object mask; @@ -5531,7 +5753,7 @@ image_ascent (img, face) struct image *img; struct face *face; { - int height = img->height + img->margin; + int height = img->height + img->vmargin; int ascent; if (img->ascent == CENTERED_IMAGE_ASCENT) @@ -5552,6 +5774,104 @@ image_ascent (img, face) return ascent; } + +/* Image background colors. */ + +static unsigned long +four_corners_best (ximg, width, height) + XImage *ximg; + unsigned long width, height; +{ + unsigned long corners[4], best; + int i, best_count; + + /* Get the colors at the corners of ximg. */ + corners[0] = XGetPixel (ximg, 0, 0); + corners[1] = XGetPixel (ximg, width - 1, 0); + corners[2] = XGetPixel (ximg, width - 1, height - 1); + corners[3] = XGetPixel (ximg, 0, height - 1); + + /* Choose the most frequently found color as background. */ + for (i = best_count = 0; i < 4; ++i) + { + int j, n; + + for (j = n = 0; j < 4; ++j) + if (corners[i] == corners[j]) + ++n; + + if (n > best_count) + best = corners[i], best_count = n; + } + + return best; +} + +/* Return the `background' field of IMG. If IMG doesn't have one yet, + it is guessed heuristically. If non-zero, XIMG is an existing XImage + object to use for the heuristic. */ + +unsigned long +image_background (img, f, ximg) + struct image *img; + struct frame *f; + XImage *ximg; +{ + if (! img->background_valid) + /* IMG doesn't have a background yet, try to guess a reasonable value. */ + { + int free_ximg = !ximg; + + if (! ximg) + ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap, + 0, 0, img->width, img->height, ~0, ZPixmap); + + img->background = four_corners_best (ximg, img->width, img->height); + + if (free_ximg) + XDestroyImage (ximg); + + img->background_valid = 1; + } + + return img->background; +} + +/* Return the `background_transparent' field of IMG. If IMG doesn't + have one yet, it is guessed heuristically. If non-zero, MASK is an + existing XImage object to use for the heuristic. */ + +int +image_background_transparent (img, f, mask) + struct image *img; + struct frame *f; + XImage *mask; +{ + if (! img->background_transparent_valid) + /* IMG doesn't have a background yet, try to guess a reasonable value. */ + { + if (img->mask) + { + int free_mask = !mask; + + if (! mask) + mask = XGetImage (FRAME_X_DISPLAY (f), img->mask, + 0, 0, img->width, img->height, ~0, ZPixmap); + + img->background_transparent + = !four_corners_best (mask, img->width, img->height); + + if (free_mask) + XDestroyImage (mask); + } + else + img->background_transparent = 0; + + img->background_transparent_valid = 1; + } + + return img->background_transparent; +} /*********************************************************************** @@ -5582,12 +5902,14 @@ x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p) { XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap); img->pixmap = None; + img->background_valid = 0; } if (mask_p && img->mask) { XFreePixmap (FRAME_X_DISPLAY (f), img->mask); img->mask = None; + img->background_transparent_valid = 0; } if (colors_p && img->ncolors) @@ -5653,6 +5975,7 @@ x_alloc_image_color (f, img, color_name, dflt) ***********************************************************************/ static void cache_image P_ ((struct frame *f, struct image *img)); +static void postprocess_image P_ ((struct frame *, struct image *)); /* Return a new, initialized image cache that is allocated from the @@ -5763,10 +6086,10 @@ clear_image_cache (f, force_p) DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache, 0, 1, 0, - "Clear the image cache of FRAME.\n\ -FRAME nil or omitted means use the selected frame.\n\ -FRAME t means clear the image caches of all frames.") - (frame) + doc: /* Clear the image cache of FRAME. +FRAME nil or omitted means use the selected frame. +FRAME t means clear the image caches of all frames. */) + (frame) Lisp_Object frame; { if (EQ (frame, Qt)) @@ -5784,6 +6107,81 @@ FRAME t means clear the image caches of all frames.") } +/* Compute masks and transform image IMG on frame F, as specified + by the image's specification, */ + +static void +postprocess_image (f, img) + struct frame *f; + struct image *img; +{ + /* Manipulation of the image's mask. */ + if (img->pixmap) + { + Lisp_Object conversion, spec; + Lisp_Object mask; + + spec = img->spec; + + /* `:heuristic-mask t' + `:mask heuristic' + means build a mask heuristically. + `:heuristic-mask (R G B)' + `:mask (heuristic (R G B))' + means build a mask from color (R G B) in the + image. + `:mask nil' + means remove a mask, if any. */ + + mask = image_spec_value (spec, QCheuristic_mask, NULL); + if (!NILP (mask)) + x_build_heuristic_mask (f, img, mask); + else + { + int found_p; + + mask = image_spec_value (spec, QCmask, &found_p); + + if (EQ (mask, Qheuristic)) + x_build_heuristic_mask (f, img, Qt); + else if (CONSP (mask) + && EQ (XCAR (mask), Qheuristic)) + { + if (CONSP (XCDR (mask))) + x_build_heuristic_mask (f, img, XCAR (XCDR (mask))); + else + x_build_heuristic_mask (f, img, XCDR (mask)); + } + else if (NILP (mask) && found_p && img->mask) + { + XFreePixmap (FRAME_X_DISPLAY (f), img->mask); + img->mask = None; + } + } + + + /* Should we apply an image transformation algorithm? */ + conversion = image_spec_value (spec, QCconversion, NULL); + if (EQ (conversion, Qdisabled)) + x_disable_image (f, img); + else if (EQ (conversion, Qlaplace)) + x_laplace (f, img); + else if (EQ (conversion, Qemboss)) + x_emboss (f, img); + else if (CONSP (conversion) + && EQ (XCAR (conversion), Qedge_detection)) + { + Lisp_Object tem; + tem = XCDR (conversion); + if (CONSP (tem)) + x_edge_detection (f, img, + Fplist_get (tem, QCmatrix), + Fplist_get (tem, QCcolor_adjustment)); + } + } +} + + /* Return the id of image with Lisp specification SPEC on frame F. SPEC must be a valid Lisp image specification (see valid_image_p). */ @@ -5817,6 +6215,8 @@ lookup_image (f, spec) /* If not found, create a new image and cache it. */ if (img == NULL) { + extern Lisp_Object Qpostscript; + BLOCK_INPUT; img = make_image (spec, hash); cache_image (f, img); @@ -5839,9 +6239,9 @@ lookup_image (f, spec) else { /* Handle image type independent image attributes - `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF'. */ - Lisp_Object ascent, margin, relief; - Lisp_Object file; + `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF', + `:background COLOR'. */ + Lisp_Object ascent, margin, relief, bg; ascent = image_spec_value (spec, QCascent, NULL); if (INTEGERP (ascent)) @@ -5851,80 +6251,40 @@ lookup_image (f, spec) margin = image_spec_value (spec, QCmargin, NULL); if (INTEGERP (margin) && XINT (margin) >= 0) - img->margin = XFASTINT (margin); + img->vmargin = img->hmargin = XFASTINT (margin); + else if (CONSP (margin) && INTEGERP (XCAR (margin)) + && INTEGERP (XCDR (margin))) + { + if (XINT (XCAR (margin)) > 0) + img->hmargin = XFASTINT (XCAR (margin)); + if (XINT (XCDR (margin)) > 0) + img->vmargin = XFASTINT (XCDR (margin)); + } relief = image_spec_value (spec, QCrelief, NULL); if (INTEGERP (relief)) { img->relief = XINT (relief); - img->margin += abs (img->relief); + img->hmargin += abs (img->relief); + img->vmargin += abs (img->relief); } - /* Manipulation of the image's mask. */ - if (img->pixmap) - { - /* `:heuristic-mask t' - `:mask heuristic' - means build a mask heuristically. - `:heuristic-mask (R G B)' - `:mask (heuristic (R G B))' - means build a mask from color (R G B) in the - image. - `:mask nil' - means remove a mask, if any. */ - - Lisp_Object mask; - - mask = image_spec_value (spec, QCheuristic_mask, NULL); - if (!NILP (mask)) - x_build_heuristic_mask (f, img, mask); - else - { - int found_p; - - mask = image_spec_value (spec, QCmask, &found_p); - - if (EQ (mask, Qheuristic)) - x_build_heuristic_mask (f, img, Qt); - else if (CONSP (mask) - && EQ (XCAR (mask), Qheuristic)) - { - if (CONSP (XCDR (mask))) - x_build_heuristic_mask (f, img, XCAR (XCDR (mask))); - else - x_build_heuristic_mask (f, img, XCDR (mask)); - } - else if (NILP (mask) && found_p && img->mask) - { - XFreePixmap (FRAME_X_DISPLAY (f), img->mask); - img->mask = None; - } - } - } - - /* Should we apply an image transformation algorithm? */ - if (img->pixmap) + if (! img->background_valid) { - Lisp_Object algorithm; - - algorithm = image_spec_value (spec, QCalgorithm, NULL); - if (EQ (algorithm, Qdisabled)) - x_disable_image (f, img); - else if (EQ (algorithm, Qlaplace)) - x_laplace (f, img); - else if (EQ (algorithm, Qemboss)) - x_emboss (f, img); - else if (CONSP (algorithm) - && EQ (XCAR (algorithm), Qedge_detection)) + bg = image_spec_value (img->spec, QCbackground, NULL); + if (!NILP (bg)) { - Lisp_Object tem; - tem = XCDR (algorithm); - if (CONSP (tem)) - x_edge_detection (f, img, - Fplist_get (tem, QCmatrix), - Fplist_get (tem, QCcolor_adjustment)); + img->background + = x_alloc_image_color (f, img, bg, + FRAME_BACKGROUND_PIXEL (f)); + img->background_valid = 1; } } + + /* Do image transformations and compute masks, unless we + don't have the image yet. */ + if (!EQ (*img->type->type, Qpostscript)) + postprocess_image (f, img); } UNBLOCK_INPUT; @@ -6121,7 +6481,7 @@ x_find_image_file (file) GCPRO2 (file_found, search_path); /* Try to find FILE in data-directory, then x-bitmap-file-path. */ - fd = openp (search_path, file, "", &file_found, 0); + fd = openp (search_path, file, Qnil, &file_found, 0); if (fd == -1) file_found = Qnil; @@ -6214,12 +6574,12 @@ static struct image_keyword xbm_format[XBM_LAST] = {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0}, {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0}, {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":foreground", IMAGE_STRING_VALUE, 0}, - {":background", IMAGE_STRING_VALUE, 0}, + {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0}, {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, {":relief", IMAGE_INTEGER_VALUE, 0}, - {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} }; @@ -6634,10 +6994,13 @@ xbm_load_image (f, img, contents, end) value = image_spec_value (img->spec, QCforeground, NULL); if (!NILP (value)) foreground = x_alloc_image_color (f, img, value, foreground); - value = image_spec_value (img->spec, QCbackground, NULL); if (!NILP (value)) - background = x_alloc_image_color (f, img, value, background); + { + background = x_alloc_image_color (f, img, value, background); + img->background = background; + img->background_valid = 1; + } img->pixmap = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f), @@ -6724,12 +7087,11 @@ xbm_load (f, img) { struct image_keyword fmt[XBM_LAST]; Lisp_Object data; - unsigned char *bitmap_data; int depth; unsigned long foreground = FRAME_FOREGROUND_PIXEL (f); unsigned long background = FRAME_BACKGROUND_PIXEL (f); char *bits; - int parsed_p, height, width; + int parsed_p; int in_memory_file_p = 0; /* See if data looks like an in-memory XBM file. */ @@ -6750,10 +7112,12 @@ xbm_load (f, img) } /* Get foreground and background colors, maybe allocate colors. */ - if (fmt[XBM_FOREGROUND].count) + if (fmt[XBM_FOREGROUND].count + && STRINGP (fmt[XBM_FOREGROUND].value)) foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value, foreground); - if (fmt[XBM_BACKGROUND].count) + if (fmt[XBM_BACKGROUND].count + && STRINGP (fmt[XBM_BACKGROUND].value)) background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value, background); @@ -6839,6 +7203,7 @@ enum xpm_keyword_index XPM_HEURISTIC_MASK, XPM_MASK, XPM_COLOR_SYMBOLS, + XPM_BACKGROUND, XPM_LAST }; @@ -6851,12 +7216,13 @@ static struct image_keyword xpm_format[XPM_LAST] = {":file", IMAGE_STRING_VALUE, 0}, {":data", IMAGE_STRING_VALUE, 0}, {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, {":relief", IMAGE_INTEGER_VALUE, 0}, - {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0} + {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} }; /* Structure describing the image type XBM. */ @@ -7120,7 +7486,7 @@ xpm_load (f, img) struct frame *f; struct image *img; { - int rc, i; + int rc; XpmAttributes attrs; Lisp_Object specified_file, color_symbols; @@ -7221,6 +7587,8 @@ xpm_load (f, img) #ifdef ALLOC_XPM_COLORS img->colors = colors_in_color_table (&img->ncolors); #else /* not ALLOC_XPM_COLORS */ + int i; + img->ncolors = attrs.nalloc_pixels; img->colors = (unsigned long *) xmalloc (img->ncolors * sizeof *img->colors); @@ -7471,15 +7839,11 @@ colors_in_color_table (n) Algorithms ***********************************************************************/ -static void x_laplace_write_row P_ ((struct frame *, long *, - int, XImage *, int)); -static void x_laplace_read_row P_ ((struct frame *, Colormap, - XColor *, int, XImage *, int)); static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int)); static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *)); static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int)); -/* Non-zero means draw a cross on images having `:algorithm +/* Non-zero means draw a cross on images having `:conversion disabled'. */ int cross_disabled_images; @@ -7801,13 +8165,14 @@ x_build_heuristic_mask (f, img, how) { Display *dpy = FRAME_X_DISPLAY (f); XImage *ximg, *mask_img; - int x, y, rc, look_at_corners_p; + int x, y, rc, use_img_background; unsigned long bg = 0; if (img->mask) { XFreePixmap (FRAME_X_DISPLAY (f), img->mask); img->mask = None; + img->background_transparent_valid = 0; } /* Create an image and pixmap serving as mask. */ @@ -7821,17 +8186,14 @@ x_build_heuristic_mask (f, img, how) ~0, ZPixmap); /* Determine the background color of ximg. If HOW is `(R G B)' - take that as color. Otherwise, try to determine the color - heuristically. */ - look_at_corners_p = 1; + take that as color. Otherwise, use the image's background color. */ + use_img_background = 1; if (CONSP (how)) { - int rgb[3], i = 0; + int rgb[3], i; - while (i < 3 - && CONSP (how) - && NATNUMP (XCAR (how))) + for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i) { rgb[i] = XFASTINT (XCAR (how)) & 0xffff; how = XCDR (how); @@ -7840,44 +8202,14 @@ x_build_heuristic_mask (f, img, how) if (i == 3 && NILP (how)) { char color_name[30]; - XColor exact, color; - Colormap cmap; - sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]); - - cmap = FRAME_X_COLORMAP (f); - if (XLookupColor (dpy, cmap, color_name, &exact, &color)) - { - bg = color.pixel; - look_at_corners_p = 0; - } + bg = x_alloc_image_color (f, img, build_string (color_name), 0); + use_img_background = 0; } } - if (look_at_corners_p) - { - unsigned long corners[4]; - int i, best_count; - - /* Get the colors at the corners of ximg. */ - corners[0] = XGetPixel (ximg, 0, 0); - corners[1] = XGetPixel (ximg, img->width - 1, 0); - corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1); - corners[3] = XGetPixel (ximg, 0, img->height - 1); - - /* Choose the most frequently found color as background. */ - for (i = best_count = 0; i < 4; ++i) - { - int j, n; - - for (j = n = 0; j < 4; ++j) - if (corners[i] == corners[j]) - ++n; - - if (n > best_count) - bg = corners[i], best_count = n; - } - } + if (use_img_background) + bg = four_corners_best (ximg, img->width, img->height); /* Set all bits in mask_img to 1 whose color in ximg is different from the background color bg. */ @@ -7885,6 +8217,9 @@ x_build_heuristic_mask (f, img, how) for (x = 0; x < img->width; ++x) XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg); + /* Fill in the background_transparent field while we have the mask handy. */ + image_background_transparent (img, f, mask_img); + /* Put mask_img into img->mask. */ x_put_x_image (f, mask_img, img->mask, img->width, img->height); x_destroy_x_image (mask_img); @@ -7934,13 +8269,13 @@ static struct image_keyword pbm_format[PBM_LAST] = {":file", IMAGE_STRING_VALUE, 0}, {":data", IMAGE_STRING_VALUE, 0}, {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, {":relief", IMAGE_INTEGER_VALUE, 0}, - {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":foreground", IMAGE_STRING_VALUE, 0}, - {":background", IMAGE_STRING_VALUE, 0} + {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} }; /* Structure describing the image type `pbm'. */ @@ -8138,10 +8473,16 @@ pbm_load (f, img) parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm); /* Get foreground and background colors, maybe allocate colors. */ - if (fmt[PBM_FOREGROUND].count) + if (fmt[PBM_FOREGROUND].count + && STRINGP (fmt[PBM_FOREGROUND].value)) fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg); - if (fmt[PBM_BACKGROUND].count) - bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg); + if (fmt[PBM_BACKGROUND].count + && STRINGP (fmt[PBM_BACKGROUND].value)) + { + bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg); + img->background = bg; + img->background_valid = 1; + } for (y = 0; y < height; ++y) for (x = 0; x < width; ++x) @@ -8204,6 +8545,10 @@ pbm_load (f, img) free the color table. */ img->colors = colors_in_color_table (&img->ncolors); free_color_table (); + + /* Maybe fill in the background field while we have ximg handy. */ + if (NILP (image_spec_value (img->spec, QCbackground, NULL))) + IMAGE_BACKGROUND (img, f, ximg); /* Put the image into a pixmap. */ x_put_x_image (f, ximg, img->pixmap, width, height); @@ -8249,6 +8594,7 @@ enum png_keyword_index PNG_ALGORITHM, PNG_HEURISTIC_MASK, PNG_MASK, + PNG_BACKGROUND, PNG_LAST }; @@ -8261,11 +8607,12 @@ static struct image_keyword png_format[PNG_LAST] = {":data", IMAGE_STRING_VALUE, 0}, {":file", IMAGE_STRING_VALUE, 0}, {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, {":relief", IMAGE_INTEGER_VALUE, 0}, - {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} + {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} }; /* Structure describing the image type `png'. */ @@ -8536,12 +8883,31 @@ png_load (f, img) simple transparency, we prefer a clipping mask. */ if (!transparent_p) { - png_color_16 *image_background; + png_color_16 *image_bg; + Lisp_Object specified_bg + = image_spec_value (img->spec, QCbackground, NULL); + + if (STRINGP (specified_bg)) + /* The user specified `:background', use that. */ + { + XColor color; + if (x_defined_color (f, XSTRING (specified_bg)->data, &color, 0)) + { + png_color_16 user_bg; + + bzero (&user_bg, sizeof user_bg); + user_bg.red = color.red; + user_bg.green = color.green; + user_bg.blue = color.blue; - if (png_get_bKGD (png_ptr, info_ptr, &image_background)) + png_set_background (png_ptr, &user_bg, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + } + } + else if (png_get_bKGD (png_ptr, info_ptr, &image_bg)) /* Image contains a background color with which to combine the image. */ - png_set_background (png_ptr, image_background, + png_set_background (png_ptr, image_bg, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); else { @@ -8654,6 +9020,18 @@ png_load (f, img) } } + if (NILP (image_spec_value (img->spec, QCbackground, NULL))) + /* Set IMG's background color from the PNG image, unless the user + overrode it. */ + { + png_color_16 *bg; + if (png_get_bKGD (png_ptr, info_ptr, &bg)) + { + img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue); + img->background_valid = 1; + } + } + /* Remember colors allocated for this image. */ img->colors = colors_in_color_table (&img->ncolors); free_color_table (); @@ -8666,6 +9044,9 @@ png_load (f, img) img->width = width; img->height = height; + /* Maybe fill in the background field while we have ximg handy. */ + IMAGE_BACKGROUND (img, f, ximg); + /* Put the image into the pixmap, then free the X image and its buffer. */ x_put_x_image (f, ximg, img->pixmap, width, height); x_destroy_x_image (ximg); @@ -8673,6 +9054,10 @@ png_load (f, img) /* Same for the mask. */ if (mask_img) { + /* Fill in the background_transparent field while we have the mask + handy. */ + image_background_transparent (img, f, mask_img); + x_put_x_image (f, mask_img, img->mask, img->width, img->height); x_destroy_x_image (mask_img); } @@ -8726,6 +9111,7 @@ enum jpeg_keyword_index JPEG_ALGORITHM, JPEG_HEURISTIC_MASK, JPEG_MASK, + JPEG_BACKGROUND, JPEG_LAST }; @@ -8738,11 +9124,12 @@ static struct image_keyword jpeg_format[JPEG_LAST] = {":data", IMAGE_STRING_VALUE, 0}, {":file", IMAGE_STRING_VALUE, 0}, {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, {":relief", IMAGE_INTEGER_VALUE, 0}, - {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} + {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} }; /* Structure describing the image type `jpeg'. */ @@ -9041,6 +9428,10 @@ jpeg_load (f, img) jpeg_destroy_decompress (&cinfo); if (fp) fclose ((FILE *) fp); + + /* Maybe fill in the background field while we have ximg handy. */ + if (NILP (image_spec_value (img->spec, QCbackground, NULL))) + IMAGE_BACKGROUND (img, f, ximg); /* Put the image into the pixmap. */ x_put_x_image (f, ximg, img->pixmap, width, height); @@ -9081,6 +9472,7 @@ enum tiff_keyword_index TIFF_ALGORITHM, TIFF_HEURISTIC_MASK, TIFF_MASK, + TIFF_BACKGROUND, TIFF_LAST }; @@ -9093,11 +9485,12 @@ static struct image_keyword tiff_format[TIFF_LAST] = {":data", IMAGE_STRING_VALUE, 0}, {":file", IMAGE_STRING_VALUE, 0}, {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, {":relief", IMAGE_INTEGER_VALUE, 0}, - {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} + {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} }; /* Structure describing the image type `tiff'. */ @@ -9246,6 +9639,34 @@ tiff_size_of_memory (data) } +static void +tiff_error_handler (title, format, ap) + const char *title, *format; + va_list ap; +{ + char buf[512]; + int len; + + len = sprintf (buf, "TIFF error: %s ", title); + vsprintf (buf + len, format, ap); + add_to_log (buf, Qnil, Qnil); +} + + +static void +tiff_warning_handler (title, format, ap) + const char *title, *format; + va_list ap; +{ + char buf[512]; + int len; + + len = sprintf (buf, "TIFF warning: %s ", title); + vsprintf (buf + len, format, ap); + add_to_log (buf, Qnil, Qnil); +} + + /* Load TIFF image IMG for use on frame F. Value is non-zero if successful. */ @@ -9269,6 +9690,9 @@ tiff_load (f, img) file = Qnil; GCPRO1 (file); + TIFFSetErrorHandler (tiff_error_handler); + TIFFSetWarningHandler (tiff_warning_handler); + if (NILP (specified_data)) { /* Read from a file */ @@ -9358,14 +9782,18 @@ tiff_load (f, img) /* Remember the colors allocated for the image. Free the color table. */ img->colors = colors_in_color_table (&img->ncolors); free_color_table (); + + img->width = width; + img->height = height; + + /* Maybe fill in the background field while we have ximg handy. */ + if (NILP (image_spec_value (img->spec, QCbackground, NULL))) + IMAGE_BACKGROUND (img, f, ximg); /* Put the image into the pixmap, then free the X image and its buffer. */ x_put_x_image (f, ximg, img->pixmap, width, height); x_destroy_x_image (ximg); xfree (buf); - - img->width = width; - img->height = height; UNGCPRO; return 1; @@ -9404,6 +9832,7 @@ enum gif_keyword_index GIF_HEURISTIC_MASK, GIF_MASK, GIF_IMAGE, + GIF_BACKGROUND, GIF_LAST }; @@ -9416,12 +9845,13 @@ static struct image_keyword gif_format[GIF_LAST] = {":data", IMAGE_STRING_VALUE, 0}, {":file", IMAGE_STRING_VALUE, 0}, {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, {":relief", IMAGE_INTEGER_VALUE, 0}, - {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0} + {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} }; /* Structure describing the image type `gif'. */ @@ -9634,7 +10064,7 @@ gif_load (f, img) { static int interlace_start[] = {0, 4, 2, 1}; static int interlace_increment[] = {8, 8, 4, 2}; - int pass, inc; + int pass; int row = interlace_start[0]; pass = 0; @@ -9669,6 +10099,10 @@ gif_load (f, img) } DGifCloseFile (gif); + + /* Maybe fill in the background field while we have ximg handy. */ + if (NILP (image_spec_value (img->spec, QCbackground, NULL))) + IMAGE_BACKGROUND (img, f, ximg); /* Put the image into the pixmap, then free the X image and its buffer. */ x_put_x_image (f, ximg, img->pixmap, width, height); @@ -9714,6 +10148,7 @@ enum gs_keyword_index GS_ALGORITHM, GS_HEURISTIC_MASK, GS_MASK, + GS_BACKGROUND, GS_LAST }; @@ -9729,11 +10164,12 @@ static struct image_keyword gs_format[GS_LAST] = {":loader", IMAGE_FUNCTION_VALUE, 0}, {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1}, {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, {":relief", IMAGE_INTEGER_VALUE, 0}, - {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} + {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} }; /* Structure describing the image type `ghostscript'. */ @@ -9889,9 +10325,13 @@ x_kill_gs_process (pixmap, f) if (c->images[i]->pixmap == pixmap) break; + /* Should someone in between have cleared the image cache, for + instance, give up. */ + if (i == c->used) + return; + /* Kill the GS process. We should have found PIXMAP in the image cache and its image should contain a process object. */ - xassert (i < c->used); img = c->images[i]; xassert (PROCESSP (img->data.lisp_val)); Fkill_process (img->data.lisp_val, Qnil); @@ -9948,6 +10388,12 @@ x_kill_gs_process (pixmap, f) UNBLOCK_INPUT; } + + /* Now that we have the pixmap, compute mask and transform the + image if requested. */ + BLOCK_INPUT; + postprocess_image (f, img); + UNBLOCK_INPUT; } @@ -9958,17 +10404,17 @@ x_kill_gs_process (pixmap, f) DEFUN ("x-change-window-property", Fx_change_window_property, Sx_change_window_property, 2, 3, 0, - "Change window property PROP to VALUE on the X window of FRAME.\n\ -PROP and VALUE must be strings. FRAME nil or omitted means use the\n\ -selected frame. Value is VALUE.") - (prop, value, frame) + doc: /* Change window property PROP to VALUE on the X window of FRAME. +PROP and VALUE must be strings. FRAME nil or omitted means use the +selected frame. Value is VALUE. */) + (prop, value, frame) Lisp_Object frame, prop, value; { struct frame *f = check_x_frame (frame); Atom prop_atom; - CHECK_STRING (prop, 1); - CHECK_STRING (value, 2); + CHECK_STRING (prop); + CHECK_STRING (value); BLOCK_INPUT; prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False); @@ -9986,15 +10432,15 @@ selected frame. Value is VALUE.") DEFUN ("x-delete-window-property", Fx_delete_window_property, Sx_delete_window_property, 1, 2, 0, - "Remove window property PROP from X window of FRAME.\n\ -FRAME nil or omitted means use the selected frame. Value is PROP.") - (prop, frame) + doc: /* Remove window property PROP from X window of FRAME. +FRAME nil or omitted means use the selected frame. Value is PROP. */) + (prop, frame) Lisp_Object prop, frame; { struct frame *f = check_x_frame (frame); Atom prop_atom; - CHECK_STRING (prop, 1); + CHECK_STRING (prop); BLOCK_INPUT; prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False); XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), prop_atom); @@ -10009,11 +10455,11 @@ FRAME nil or omitted means use the selected frame. Value is PROP.") DEFUN ("x-window-property", Fx_window_property, Sx_window_property, 1, 2, 0, - "Value is the value of window property PROP on FRAME.\n\ -If FRAME is nil or omitted, use the selected frame. Value is nil\n\ -if FRAME hasn't a property with name PROP or if PROP has no string\n\ -value.") - (prop, frame) + doc: /* Value is the value of window property PROP on FRAME. +If FRAME is nil or omitted, use the selected frame. Value is nil +if FRAME hasn't a property with name PROP or if PROP has no string +value. */) + (prop, frame) Lisp_Object prop, frame; { struct frame *f = check_x_frame (frame); @@ -10025,7 +10471,7 @@ value.") int actual_format; unsigned long actual_size, bytes_remaining; - CHECK_STRING (prop, 1); + CHECK_STRING (prop); BLOCK_INPUT; prop_atom = XInternAtom (FRAME_X_DISPLAY (f), XSTRING (prop)->data, False); rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), @@ -10045,7 +10491,7 @@ value.") &actual_type, &actual_format, &actual_size, &bytes_remaining, (unsigned char **) &tmp_data); - if (rc == Success) + if (rc == Success && tmp_data) prop_value = make_string (tmp_data, size); XFree (tmp_data); @@ -10062,138 +10508,149 @@ value.") ***********************************************************************/ /* If non-null, an asynchronous timer that, when it expires, displays - a busy cursor on all frames. */ + an hourglass cursor on all frames. */ -static struct atimer *busy_cursor_atimer; +static struct atimer *hourglass_atimer; -/* Non-zero means a busy cursor is currently shown. */ +/* Non-zero means an hourglass cursor is currently shown. */ -static int busy_cursor_shown_p; +static int hourglass_shown_p; -/* Number of seconds to wait before displaying a busy cursor. */ +/* Number of seconds to wait before displaying an hourglass cursor. */ -static Lisp_Object Vbusy_cursor_delay; +static Lisp_Object Vhourglass_delay; -/* Default number of seconds to wait before displaying a busy +/* Default number of seconds to wait before displaying an hourglass cursor. */ -#define DEFAULT_BUSY_CURSOR_DELAY 1 +#define DEFAULT_HOURGLASS_DELAY 1 /* Function prototypes. */ -static void show_busy_cursor P_ ((struct atimer *)); -static void hide_busy_cursor P_ ((void)); +static void show_hourglass P_ ((struct atimer *)); +static void hide_hourglass P_ ((void)); -/* Cancel a currently active busy-cursor timer, and start a new one. */ +/* Cancel a currently active hourglass timer, and start a new one. */ void -start_busy_cursor () +start_hourglass () { EMACS_TIME delay; int secs, usecs = 0; - cancel_busy_cursor (); + cancel_hourglass (); - if (INTEGERP (Vbusy_cursor_delay) - && XINT (Vbusy_cursor_delay) > 0) - secs = XFASTINT (Vbusy_cursor_delay); - else if (FLOATP (Vbusy_cursor_delay) - && XFLOAT_DATA (Vbusy_cursor_delay) > 0) + if (INTEGERP (Vhourglass_delay) + && XINT (Vhourglass_delay) > 0) + secs = XFASTINT (Vhourglass_delay); + else if (FLOATP (Vhourglass_delay) + && XFLOAT_DATA (Vhourglass_delay) > 0) { Lisp_Object tem; - tem = Ftruncate (Vbusy_cursor_delay, Qnil); + tem = Ftruncate (Vhourglass_delay, Qnil); secs = XFASTINT (tem); - usecs = (XFLOAT_DATA (Vbusy_cursor_delay) - secs) * 1000000; + usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000; } else - secs = DEFAULT_BUSY_CURSOR_DELAY; + secs = DEFAULT_HOURGLASS_DELAY; EMACS_SET_SECS_USECS (delay, secs, usecs); - busy_cursor_atimer = start_atimer (ATIMER_RELATIVE, delay, - show_busy_cursor, NULL); + hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay, + show_hourglass, NULL); } -/* Cancel the busy cursor timer if active, hide a busy cursor if +/* Cancel the hourglass cursor timer if active, hide a busy cursor if shown. */ void -cancel_busy_cursor () +cancel_hourglass () { - if (busy_cursor_atimer) + if (hourglass_atimer) { - cancel_atimer (busy_cursor_atimer); - busy_cursor_atimer = NULL; + cancel_atimer (hourglass_atimer); + hourglass_atimer = NULL; } - if (busy_cursor_shown_p) - hide_busy_cursor (); + if (hourglass_shown_p) + hide_hourglass (); } -/* Timer function of busy_cursor_atimer. TIMER is equal to - busy_cursor_atimer. +/* Timer function of hourglass_atimer. TIMER is equal to + hourglass_atimer. - Display a busy cursor on all frames by mapping the frames' - busy_window. Set the busy_p flag in the frames' output_data.x - structure to indicate that a busy cursor is shown on the - frames. */ + Display an hourglass pointer on all frames by mapping the frames' + hourglass_window. Set the hourglass_p flag in the frames' + output_data.x structure to indicate that an hourglass cursor is + shown on the frames. */ static void -show_busy_cursor (timer) +show_hourglass (timer) struct atimer *timer; { /* The timer implementation will cancel this timer automatically - after this function has run. Set busy_cursor_atimer to null + after this function has run. Set hourglass_atimer to null so that we know the timer doesn't have to be canceled. */ - busy_cursor_atimer = NULL; + hourglass_atimer = NULL; - if (!busy_cursor_shown_p) + if (!hourglass_shown_p) { Lisp_Object rest, frame; BLOCK_INPUT; FOR_EACH_FRAME (rest, frame) - if (FRAME_X_P (XFRAME (frame))) - { - struct frame *f = XFRAME (frame); - - f->output_data.x->busy_p = 1; + { + struct frame *f = XFRAME (frame); + + if (FRAME_LIVE_P (f) && FRAME_X_P (f) && FRAME_X_DISPLAY (f)) + { + Display *dpy = FRAME_X_DISPLAY (f); + +#ifdef USE_X_TOOLKIT + if (f->output_data.x->widget) +#else + if (FRAME_OUTER_WINDOW (f)) +#endif + { + f->output_data.x->hourglass_p = 1; - if (!f->output_data.x->busy_window) - { - unsigned long mask = CWCursor; - XSetWindowAttributes attrs; + if (!f->output_data.x->hourglass_window) + { + unsigned long mask = CWCursor; + XSetWindowAttributes attrs; - attrs.cursor = f->output_data.x->busy_cursor; + attrs.cursor = f->output_data.x->hourglass_cursor; - f->output_data.x->busy_window - = XCreateWindow (FRAME_X_DISPLAY (f), - FRAME_OUTER_WINDOW (f), - 0, 0, 32000, 32000, 0, 0, - InputOnly, - CopyFromParent, - mask, &attrs); - } + f->output_data.x->hourglass_window + = XCreateWindow (dpy, FRAME_OUTER_WINDOW (f), + 0, 0, 32000, 32000, 0, 0, + InputOnly, + CopyFromParent, + mask, &attrs); + } - XMapRaised (FRAME_X_DISPLAY (f), f->output_data.x->busy_window); - XFlush (FRAME_X_DISPLAY (f)); - } + XMapRaised (dpy, f->output_data.x->hourglass_window); + XFlush (dpy); + } + } + } - busy_cursor_shown_p = 1; + hourglass_shown_p = 1; UNBLOCK_INPUT; } } -/* Hide the busy cursor on all frames, if it is currently shown. */ +/* Hide the hourglass pointer on all frames, if it is currently + shown. */ static void -hide_busy_cursor () +hide_hourglass () { - if (busy_cursor_shown_p) + if (hourglass_shown_p) { Lisp_Object rest, frame; @@ -10204,17 +10661,18 @@ hide_busy_cursor () if (FRAME_X_P (f) /* Watch out for newly created frames. */ - && f->output_data.x->busy_window) + && f->output_data.x->hourglass_window) { - XUnmapWindow (FRAME_X_DISPLAY (f), f->output_data.x->busy_window); - /* Sync here because XTread_socket looks at the busy_p flag - that is reset to zero below. */ + XUnmapWindow (FRAME_X_DISPLAY (f), + f->output_data.x->hourglass_window); + /* Sync here because XTread_socket looks at the + hourglass_p flag that is reset to zero below. */ XSync (FRAME_X_DISPLAY (f), False); - f->output_data.x->busy_p = 0; + f->output_data.x->hourglass_p = 0; } } - busy_cursor_shown_p = 0; + hourglass_shown_p = 0; UNBLOCK_INPUT; } } @@ -10226,11 +10684,13 @@ hide_busy_cursor () ***********************************************************************/ static Lisp_Object x_create_tip_frame P_ ((struct x_display_info *, - Lisp_Object)); + Lisp_Object, Lisp_Object)); +static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object, + Lisp_Object, int, int, int *, int *)); -/* The frame of a currently visible tooltip, or null. */ +/* The frame of a currently visible tooltip. */ -struct frame *tip_frame; +Lisp_Object tip_frame; /* If non-nil, a timer started that hides the last tooltip when it fires. */ @@ -10238,22 +10698,58 @@ struct frame *tip_frame; Lisp_Object tip_timer; Window tip_window; +/* If non-nil, a vector of 3 elements containing the last args + with which x-show-tip was called. See there. */ + +Lisp_Object last_show_tip_args; + +/* Maximum size for tooltips; a cons (COLUMNS . ROWS). */ + +Lisp_Object Vx_max_tooltip_size; + + +static Lisp_Object +unwind_create_tip_frame (frame) + Lisp_Object frame; +{ + Lisp_Object deleted; + + deleted = unwind_create_frame (frame); + if (EQ (deleted, Qt)) + { + tip_window = None; + tip_frame = Qnil; + } + + return deleted; +} + + /* Create a frame for a tooltip on the display described by DPYINFO. - PARMS is a list of frame parameters. Value is the frame. */ + PARMS is a list of frame parameters. TEXT is the string to + display in the tip frame. Value is the frame. + + Note that functions called here, esp. x_default_parameter can + signal errors, for instance when a specified color name is + undefined. We have to make sure that we're in a consistent state + when this happens. */ static Lisp_Object -x_create_tip_frame (dpyinfo, parms) +x_create_tip_frame (dpyinfo, parms, text) struct x_display_info *dpyinfo; - Lisp_Object parms; + Lisp_Object parms, text; { struct frame *f; Lisp_Object frame, tem; Lisp_Object name; long window_prompting = 0; int width, height; - int count = specpdl_ptr - specpdl; + int count = BINDING_STACK_SIZE (); struct gcpro gcpro1, gcpro2, gcpro3; struct kboard *kb; + int face_change_count_before = face_change_count; + Lisp_Object buffer; + struct buffer *old_buffer; check_x (); @@ -10277,10 +10773,25 @@ x_create_tip_frame (dpyinfo, parms) frame = Qnil; GCPRO3 (parms, name, frame); - tip_frame = f = make_frame (1); + f = make_frame (1); XSETFRAME (frame, f); + + buffer = Fget_buffer_create (build_string (" *tip*")); + Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer); + old_buffer = current_buffer; + set_buffer_internal_1 (XBUFFER (buffer)); + current_buffer->truncate_lines = Qnil; + Ferase_buffer (); + Finsert (1, &text); + set_buffer_internal_1 (old_buffer); + FRAME_CAN_HAVE_SCROLL_BARS (f) = 0; + record_unwind_protect (unwind_create_tip_frame, frame); + /* By setting the output method, we're essentially saying that + the frame is live, as per FRAME_LIVE_P. If we get a signal + from this point on, x_destroy_window might screw up reference + counts etc. */ f->output_method = output_x_window; f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output)); bzero (f->output_data.x, sizeof (struct x_output)); @@ -10288,8 +10799,16 @@ x_create_tip_frame (dpyinfo, parms) f->output_data.x->fontset = -1; f->output_data.x->scroll_bar_foreground_pixel = -1; f->output_data.x->scroll_bar_background_pixel = -1; +#ifdef USE_TOOLKIT_SCROLL_BARS + f->output_data.x->scroll_bar_top_shadow_pixel = -1; + f->output_data.x->scroll_bar_bottom_shadow_pixel = -1; +#endif /* USE_TOOLKIT_SCROLL_BARS */ f->icon_name = Qnil; FRAME_X_DISPLAY_INFO (f) = dpyinfo; +#if GLYPH_DEBUG + image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount; + dpyinfo_refcount = dpyinfo->reference_count; +#endif /* GLYPH_DEBUG */ #ifdef MULTI_KBOARD FRAME_KBOARD (f) = kb; #endif @@ -10334,8 +10853,8 @@ x_create_tip_frame (dpyinfo, parms) specbind (Qx_resource_name, name); } - /* Extract the window parameters from the supplied values - that are needed to determine window geometry. */ + /* Extract the window parameters from the supplied values that are + needed to determine window geometry. */ { Lisp_Object font; @@ -10482,6 +11001,26 @@ x_create_tip_frame (dpyinfo, parms) SET_FRAME_WIDTH (f, 0); change_frame_size (f, height, width, 1, 0, 0); + /* Set up faces after all frame parameters are known. This call + also merges in face attributes specified for new frames. + + Frame parameters may be changed if .Xdefaults contains + specifications for the default font. For example, if there is an + `Emacs.default.attributeBackground: pink', the `background-color' + attribute of the frame get's set, which let's the internal border + of the tooltip frame appear in pink. Prevent this. */ + { + Lisp_Object bg = Fframe_parameter (frame, Qbackground_color); + + /* Set tip_frame here, so that */ + tip_frame = frame; + call1 (Qface_set_after_frame_default, frame); + + if (!EQ (bg, Fframe_parameter (frame, Qbackground_color))) + Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg), + Qnil)); + } + f->no_split = 1; UNGCPRO; @@ -10495,69 +11034,165 @@ x_create_tip_frame (dpyinfo, parms) its display. */ FRAME_X_DISPLAY_INFO (f)->reference_count++; + /* Setting attributes of faces of the tooltip frame from resources + and similar will increment face_change_count, which leads to the + clearing of all current matrices. Since this isn't necessary + here, avoid it by resetting face_change_count to the value it + had before we created the tip frame. */ + face_change_count = face_change_count_before; + + /* Discard the unwind_protect. */ return unbind_to (count, frame); } +/* Compute where to display tip frame F. PARMS is the list of frame + parameters for F. DX and DY are specified offsets from the current + location of the mouse. WIDTH and HEIGHT are the width and height + of the tooltip. Return coordinates relative to the root window of + the display in *ROOT_X, and *ROOT_Y. */ + +static void +compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y) + struct frame *f; + Lisp_Object parms, dx, dy; + int width, height; + int *root_x, *root_y; +{ + Lisp_Object left, top; + int win_x, win_y; + Window root, child; + unsigned pmask; + + /* User-specified position? */ + left = Fcdr (Fassq (Qleft, parms)); + top = Fcdr (Fassq (Qtop, parms)); + + /* Move the tooltip window where the mouse pointer is. Resize and + show it. */ + if (!INTEGERP (left) && !INTEGERP (top)) + { + BLOCK_INPUT; + XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window, + &root, &child, root_x, root_y, &win_x, &win_y, &pmask); + UNBLOCK_INPUT; + } + + if (INTEGERP (top)) + *root_y = XINT (top); + else if (*root_y + XINT (dy) - height < 0) + *root_y -= XINT (dy); + else + { + *root_y -= height; + *root_y += XINT (dy); + } + + if (INTEGERP (left)) + *root_x = XINT (left); + else if (*root_x + XINT (dx) + width > FRAME_X_DISPLAY_INFO (f)->width) + *root_x -= width + XINT (dx); + else + *root_x += XINT (dx); +} + + DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, - "Show STRING in a \"tooltip\" window on frame FRAME.\n\ -A tooltip window is a small X window displaying a string.\n\ -\n\ -FRAME nil or omitted means use the selected frame.\n\ -\n\ -PARMS is an optional list of frame parameters which can be\n\ -used to change the tooltip's appearance.\n\ -\n\ -Automatically hide the tooltip after TIMEOUT seconds.\n\ -TIMEOUT nil means use the default timeout of 5 seconds.\n\ -\n\ -If the list of frame parameters PARAMS contains a `left' parameters,\n\ -the tooltip is displayed at that x-position. Otherwise it is\n\ -displayed at the mouse position, with offset DX added (default is 5 if\n\ -DX isn't specified). Likewise for the y-position; if a `top' frame\n\ -parameter is specified, it determines the y-position of the tooltip\n\ -window, otherwise it is displayed at the mouse position, with offset\n\ -DY added (default is -10).") - (string, frame, parms, timeout, dx, dy) + doc: /* Show STRING in a "tooltip" window on frame FRAME. +A tooltip window is a small X window displaying a string. + +FRAME nil or omitted means use the selected frame. + +PARMS is an optional list of frame parameters which can be used to +change the tooltip's appearance. + +Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil +means use the default timeout of 5 seconds. + +If the list of frame parameters PARAMS contains a `left' parameters, +the tooltip is displayed at that x-position. Otherwise it is +displayed at the mouse position, with offset DX added (default is 5 if +DX isn't specified). Likewise for the y-position; if a `top' frame +parameter is specified, it determines the y-position of the tooltip +window, otherwise it is displayed at the mouse position, with offset +DY added (default is -10). + +A tooltip's maximum size is specified by `x-max-tooltip-size'. +Text larger than the specified size is clipped. */) + (string, frame, parms, timeout, dx, dy) Lisp_Object string, frame, parms, timeout, dx, dy; { struct frame *f; struct window *w; - Window root, child; - Lisp_Object buffer, top, left; + int root_x, root_y; struct buffer *old_buffer; struct text_pos pos; int i, width, height; - int root_x, root_y, win_x, win_y; - unsigned pmask; struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; int old_windows_or_buffers_changed = windows_or_buffers_changed; - int count = specpdl_ptr - specpdl; + int count = BINDING_STACK_SIZE (); specbind (Qinhibit_redisplay, Qt); GCPRO4 (string, parms, frame, timeout); - CHECK_STRING (string, 0); + CHECK_STRING (string); f = check_x_frame (frame); if (NILP (timeout)) timeout = make_number (5); else - CHECK_NATNUM (timeout, 2); + CHECK_NATNUM (timeout); if (NILP (dx)) dx = make_number (5); else - CHECK_NUMBER (dx, 5); + CHECK_NUMBER (dx); if (NILP (dy)) dy = make_number (-10); else - CHECK_NUMBER (dy, 6); + CHECK_NUMBER (dy); + + if (NILP (last_show_tip_args)) + last_show_tip_args = Fmake_vector (make_number (3), Qnil); + + if (!NILP (tip_frame)) + { + Lisp_Object last_string = AREF (last_show_tip_args, 0); + Lisp_Object last_frame = AREF (last_show_tip_args, 1); + Lisp_Object last_parms = AREF (last_show_tip_args, 2); + + if (EQ (frame, last_frame) + && !NILP (Fequal (last_string, string)) + && !NILP (Fequal (last_parms, parms))) + { + struct frame *f = XFRAME (tip_frame); + + /* Only DX and DY have changed. */ + if (!NILP (tip_timer)) + { + Lisp_Object timer = tip_timer; + tip_timer = Qnil; + call1 (Qcancel_timer, timer); + } + + BLOCK_INPUT; + compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f), + PIXEL_HEIGHT (f), &root_x, &root_y); + XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + root_x, root_y); + UNBLOCK_INPUT; + goto start_timer; + } + } /* Hide a previous tip, if any. */ Fx_hide_tip (); + ASET (last_show_tip_args, 0, string); + ASET (last_show_tip_args, 1, frame); + ASET (last_show_tip_args, 2, parms); + /* Add default values to frame parameters. */ if (NILP (Fassq (Qname, parms))) parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms); @@ -10573,26 +11208,36 @@ DY added (default is -10).") /* Create a frame for the tooltip, and record it in the global variable tip_frame. */ - frame = x_create_tip_frame (FRAME_X_DISPLAY_INFO (f), parms); - tip_frame = f = XFRAME (frame); + frame = x_create_tip_frame (FRAME_X_DISPLAY_INFO (f), parms, string); + f = XFRAME (frame); - /* Set up the frame's root window. Currently we use a size of 80 - columns x 40 lines. If someone wants to show a larger tip, he - will loose. I don't think this is a realistic case. */ + /* Set up the frame's root window. */ w = XWINDOW (FRAME_ROOT_WINDOW (f)); w->left = w->top = make_number (0); - w->width = make_number (80); - w->height = make_number (40); + + if (CONSP (Vx_max_tooltip_size) + && INTEGERP (XCAR (Vx_max_tooltip_size)) + && XINT (XCAR (Vx_max_tooltip_size)) > 0 + && INTEGERP (XCDR (Vx_max_tooltip_size)) + && XINT (XCDR (Vx_max_tooltip_size)) > 0) + { + w->width = XCAR (Vx_max_tooltip_size); + w->height = XCDR (Vx_max_tooltip_size); + } + else + { + w->width = make_number (80); + w->height = make_number (40); + } + + f->window_width = XINT (w->width); adjust_glyphs (f); w->pseudo_window_p = 1; /* Display the tooltip text in a temporary buffer. */ - buffer = Fget_buffer_create (build_string (" *tip*")); - Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer); old_buffer = current_buffer; - set_buffer_internal_1 (XBUFFER (buffer)); - Ferase_buffer (); - Finsert (1, &string); + set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer)); + current_buffer->truncate_lines = Qnil; clear_glyph_matrix (w->desired_matrix); clear_glyph_matrix (w->current_matrix); SET_TEXT_POS (pos, BEGV, BEGV_BYTE); @@ -10632,31 +11277,16 @@ DY added (default is -10).") height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f); width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f); - /* User-specified position? */ - left = Fcdr (Fassq (Qleft, parms)); - top = Fcdr (Fassq (Qtop, parms)); - /* Move the tooltip window where the mouse pointer is. Resize and show it. */ - BLOCK_INPUT; - XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window, - &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask); - UNBLOCK_INPUT; + compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y); - root_x += XINT (dx); - root_y += XINT (dy); - - if (INTEGERP (left)) - root_x = XINT (left); - if (INTEGERP (top)) - root_y = XINT (top); - BLOCK_INPUT; XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - root_x, root_y - height, width, height); + root_x, root_y, width, height); XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); UNBLOCK_INPUT; - + /* Draw into the window. */ w->must_be_updated_p = 1; update_single_window (w, 1); @@ -10665,6 +11295,7 @@ DY added (default is -10).") set_buffer_internal_1 (old_buffer); windows_or_buffers_changed = old_windows_or_buffers_changed; + start_timer: /* Let the tip disappear after timeout seconds. */ tip_timer = call3 (intern ("run-at-time"), timeout, Qnil, intern ("x-hide-tip")); @@ -10675,29 +11306,34 @@ DY added (default is -10).") DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0, - "Hide the current tooltip window, if there is any.\n\ -Value is t is tooltip was open, nil otherwise.") - () + doc: /* Hide the current tooltip window, if there is any. +Value is t if tooltip was open, nil otherwise. */) + () { - int count = specpdl_ptr - specpdl; - int deleted_p = 0; + int count; + Lisp_Object deleted, frame, timer; + struct gcpro gcpro1, gcpro2; + + /* Return quickly if nothing to do. */ + if (NILP (tip_timer) && NILP (tip_frame)) + return Qnil; + + frame = tip_frame; + timer = tip_timer; + GCPRO2 (frame, timer); + tip_frame = tip_timer = deleted = Qnil; + count = BINDING_STACK_SIZE (); specbind (Qinhibit_redisplay, Qt); + specbind (Qinhibit_quit, Qt); - if (!NILP (tip_timer)) - { - call1 (intern ("cancel-timer"), tip_timer); - tip_timer = Qnil; - } + if (!NILP (timer)) + call1 (Qcancel_timer, timer); - if (tip_frame) + if (FRAMEP (frame)) { - Lisp_Object frame; - - XSETFRAME (frame, tip_frame); - Fdelete_frame (frame, Qt); - tip_frame = NULL; - deleted_p = 1; + Fdelete_frame (frame, Qnil); + deleted = Qt; #ifdef USE_LUCID /* Bloodcurdling hack alert: The Lucid menu bar widget's @@ -10707,9 +11343,9 @@ Value is t is tooltip was open, nil otherwise.") struct frame *f = SELECTED_FRAME (); Widget w = f->output_data.x->menubar_widget; extern void xlwmenu_redisplay P_ ((Widget)); - + if (!DoesSaveUnders (FRAME_X_DISPLAY_INFO (f)->screen) - && w != None) + && w != NULL) { BLOCK_INPUT; xlwmenu_redisplay (w); @@ -10719,7 +11355,8 @@ Value is t is tooltip was open, nil otherwise.") #endif /* USE_LUCID */ } - return unbind_to (count, deleted_p ? Qt : Qnil); + UNGCPRO; + return unbind_to (count, deleted); } @@ -10743,13 +11380,28 @@ file_dialog_cb (widget, client_data, call_data) } +/* Callback for unmapping a file selection dialog. This is used to + capture the case where a dialog is closed via a window manager's + closer button, for example. Using a XmNdestroyCallback didn't work + in this case. */ + +static void +file_dialog_unmap_cb (widget, client_data, call_data) + Widget widget; + XtPointer call_data, client_data; +{ + int *result = (int *) client_data; + *result = XmCR_CANCEL; +} + + DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0, - "Read file name, prompting with PROMPT in directory DIR.\n\ -Use a file selection dialog.\n\ -Select DEFAULT-FILENAME in the dialog's file selection box, if\n\ -specified. Don't let the user enter a file name in the file\n\ -selection dialog's entry field, if MUSTMATCH is non-nil.") - (prompt, dir, default_filename, mustmatch) + doc: /* Read file name, prompting with PROMPT in directory DIR. +Use a file selection dialog. +Select DEFAULT-FILENAME in the dialog's file selection box, if +specified. Don't let the user enter a file name in the file +selection dialog's entry field, if MUSTMATCH is non-nil. */) + (prompt, dir, default_filename, mustmatch) Lisp_Object prompt, dir, default_filename, mustmatch; { int result; @@ -10759,15 +11411,13 @@ selection dialog's entry field, if MUSTMATCH is non-nil.") Arg al[10]; int ac = 0; extern XtAppContext Xt_app_con; - char *title; XmString dir_xmstring, pattern_xmstring; - int popup_activated_flag; int count = specpdl_ptr - specpdl; struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; GCPRO5 (prompt, dir, default_filename, mustmatch, file); - CHECK_STRING (prompt, 0); - CHECK_STRING (dir, 1); + CHECK_STRING (prompt); + CHECK_STRING (dir); /* Prevent redisplay. */ specbind (Qinhibit_redisplay, Qt); @@ -10795,6 +11445,8 @@ selection dialog's entry field, if MUSTMATCH is non-nil.") (XtPointer) &result); XtAddCallback (dialog, XmNcancelCallback, file_dialog_cb, (XtPointer) &result); + XtAddCallback (dialog, XmNunmapCallback, file_dialog_unmap_cb, + (XtPointer) &result); /* Disable the help button since we can't display help. */ help = XmFileSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON); @@ -10846,38 +11498,18 @@ selection dialog's entry field, if MUSTMATCH is non-nil.") XmListSetPos (list, item_pos); } -#ifdef HAVE_MOTIF_2_1 - - /* Process events until the user presses Cancel or OK. */ + /* Process events until the user presses Cancel or OK. Block + and unblock input here so that we get a chance of processing + expose events. */ + UNBLOCK_INPUT; result = 0; - while (result == 0 || XtAppPending (Xt_app_con)) - XtAppProcessEvent (Xt_app_con, XtIMAll); - -#else /* not HAVE_MOTIF_2_1 */ - - /* Process all events until the user presses Cancel or OK. */ - for (result = 0; result == 0;) + while (result == 0) { - XEvent event; - Widget widget, parent; - - XtAppNextEvent (Xt_app_con, &event); - - /* See if the receiver of the event is one of the widgets of - the file selection dialog. If so, dispatch it. If not, - discard it. */ - widget = XtWindowToWidget (event.xany.display, event.xany.window); - parent = widget; - while (parent && parent != dialog) - parent = XtParent (parent); - - if (parent == dialog - || (event.type == Expose - && !process_expose_from_menu (event))) - XtDispatchEvent (&event); + BLOCK_INPUT; + XtAppProcessEvent (Xt_app_con, XtIMAll); + UNBLOCK_INPUT; } - -#endif /* not HAVE_MOTIF_2_1 */ + BLOCK_INPUT; /* Get the result. */ if (result == XmCR_OK) @@ -10911,6 +11543,93 @@ selection dialog's entry field, if MUSTMATCH is non-nil.") +/*********************************************************************** + Keyboard + ***********************************************************************/ + +#ifdef HAVE_XKBGETKEYBOARD +#include +#include +#endif + +DEFUN ("x-backspace-delete-keys-p", Fx_backspace_delete_keys_p, + Sx_backspace_delete_keys_p, 0, 1, 0, + doc: /* Check if both Backspace and Delete keys are on the keyboard of FRAME. +FRAME nil means use the selected frame. +Value is t if we know that both keys are present, and are mapped to the +usual X keysyms. */) + (frame) + Lisp_Object frame; +{ +#ifdef HAVE_XKBGETKEYBOARD + XkbDescPtr kb; + struct frame *f = check_x_frame (frame); + Display *dpy = FRAME_X_DISPLAY (f); + Lisp_Object have_keys; + int major, minor, op, event, error; + + BLOCK_INPUT; + + /* Check library version in case we're dynamically linked. */ + major = XkbMajorVersion; + minor = XkbMinorVersion; + if (!XkbLibraryVersion (&major, &minor)) + { + UNBLOCK_INPUT; + return Qnil; + } + + /* Check that the server supports XKB. */ + major = XkbMajorVersion; + minor = XkbMinorVersion; + if (!XkbQueryExtension (dpy, &op, &event, &error, &major, &minor)) + { + UNBLOCK_INPUT; + return Qnil; + } + + have_keys = Qnil; + kb = XkbGetMap (dpy, XkbAllMapComponentsMask, XkbUseCoreKbd); + if (kb) + { + int delete_keycode = 0, backspace_keycode = 0, i; + + if (XkbGetNames (dpy, XkbAllNamesMask, kb) == Success) + { + for (i = kb->min_key_code; + (i < kb->max_key_code + && (delete_keycode == 0 || backspace_keycode == 0)); + ++i) + { + /* The XKB symbolic key names can be seen most easily in + the PS file generated by `xkbprint -label name + $DISPLAY'. */ + if (bcmp ("DELE", kb->names->keys[i].name, 4) == 0) + delete_keycode = i; + else if (bcmp ("BKSP", kb->names->keys[i].name, 4) == 0) + backspace_keycode = i; + } + + XkbFreeNames (kb, 0, True); + } + + XkbFreeClientMap (kb, 0, True); + + if (delete_keycode + && backspace_keycode + && XKeysymToKeycode (dpy, XK_Delete) == delete_keycode + && XKeysymToKeycode (dpy, XK_BackSpace) == backspace_keycode) + have_keys = Qt; + } + UNBLOCK_INPUT; + return have_keys; +#else /* not HAVE_XKBGETKEYBOARD */ + return Qnil; +#endif /* not HAVE_XKBGETKEYBOARD */ +} + + + /*********************************************************************** Initialization ***********************************************************************/ @@ -10996,6 +11715,10 @@ syms_of_xfns () staticpro (&Qcenter); Qcompound_text = intern ("compound-text"); staticpro (&Qcompound_text); + Qcancel_timer = intern ("cancel-timer"); + staticpro (&Qcancel_timer); + Qwait_for_wm = intern ("wait-for-wm"); + staticpro (&Qwait_for_wm); /* This is the end of symbol initialization. */ /* Text property `display' should be nonsticky by default. */ @@ -11029,117 +11752,134 @@ syms_of_xfns () init_x_parm_symbols (); DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images, - "Non-nil means always draw a cross over disabled images.\n\ -Disabled images are those having an `:algorithm disabled' property.\n\ -A cross is always drawn on black & white displays."); + doc: /* Non-nil means always draw a cross over disabled images. +Disabled images are those having an `:conversion disabled' property. +A cross is always drawn on black & white displays. */); cross_disabled_images = 0; DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path, - "List of directories to search for bitmap files for X."); + doc: /* List of directories to search for bitmap files for X. */); Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS); DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape, - "The shape of the pointer when over text.\n\ -Changing the value does not affect existing frames\n\ -unless you set the mouse color."); + doc: /* The shape of the pointer when over text. +Changing the value does not affect existing frames +unless you set the mouse color. */); Vx_pointer_shape = Qnil; DEFVAR_LISP ("x-resource-name", &Vx_resource_name, - "The name Emacs uses to look up X resources.\n\ -`x-get-resource' uses this as the first component of the instance name\n\ -when requesting resource values.\n\ -Emacs initially sets `x-resource-name' to the name under which Emacs\n\ -was invoked, or to the value specified with the `-name' or `-rn'\n\ -switches, if present.\n\ -\n\ -It may be useful to bind this variable locally around a call\n\ -to `x-get-resource'. See also the variable `x-resource-class'."); + doc: /* The name Emacs uses to look up X resources. +`x-get-resource' uses this as the first component of the instance name +when requesting resource values. +Emacs initially sets `x-resource-name' to the name under which Emacs +was invoked, or to the value specified with the `-name' or `-rn' +switches, if present. + +It may be useful to bind this variable locally around a call +to `x-get-resource'. See also the variable `x-resource-class'. */); Vx_resource_name = Qnil; DEFVAR_LISP ("x-resource-class", &Vx_resource_class, - "The class Emacs uses to look up X resources.\n\ -`x-get-resource' uses this as the first component of the instance class\n\ -when requesting resource values.\n\ -Emacs initially sets `x-resource-class' to \"Emacs\".\n\ -\n\ -Setting this variable permanently is not a reasonable thing to do,\n\ -but binding this variable locally around a call to `x-get-resource'\n\ -is a reasonable practice. See also the variable `x-resource-name'."); + doc: /* The class Emacs uses to look up X resources. +`x-get-resource' uses this as the first component of the instance class +when requesting resource values. + +Emacs initially sets `x-resource-class' to "Emacs". + +Setting this variable permanently is not a reasonable thing to do, +but binding this variable locally around a call to `x-get-resource' +is a reasonable practice. See also the variable `x-resource-name'. */); Vx_resource_class = build_string (EMACS_CLASS); #if 0 /* This doesn't really do anything. */ DEFVAR_LISP ("x-nontext-pointer-shape", &Vx_nontext_pointer_shape, - "The shape of the pointer when not over text.\n\ -This variable takes effect when you create a new frame\n\ -or when you set the mouse color."); + doc: /* The shape of the pointer when not over text. +This variable takes effect when you create a new frame +or when you set the mouse color. */); #endif Vx_nontext_pointer_shape = Qnil; - DEFVAR_LISP ("x-busy-pointer-shape", &Vx_busy_pointer_shape, - "The shape of the pointer when Emacs is busy.\n\ -This variable takes effect when you create a new frame\n\ -or when you set the mouse color."); - Vx_busy_pointer_shape = Qnil; + DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape, + doc: /* The shape of the pointer when Emacs is busy. +This variable takes effect when you create a new frame +or when you set the mouse color. */); + Vx_hourglass_pointer_shape = Qnil; - DEFVAR_BOOL ("display-busy-cursor", &display_busy_cursor_p, - "Non-zero means Emacs displays a busy cursor on window systems."); - display_busy_cursor_p = 1; + DEFVAR_BOOL ("display-hourglass", &display_hourglass_p, + doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */); + display_hourglass_p = 1; - DEFVAR_LISP ("busy-cursor-delay", &Vbusy_cursor_delay, - "*Seconds to wait before displaying a busy-cursor.\n\ -Value must be an integer or float."); - Vbusy_cursor_delay = make_number (DEFAULT_BUSY_CURSOR_DELAY); + DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay, + doc: /* *Seconds to wait before displaying an hourglass pointer. +Value must be an integer or float. */); + Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY); #if 0 /* This doesn't really do anything. */ DEFVAR_LISP ("x-mode-pointer-shape", &Vx_mode_pointer_shape, - "The shape of the pointer when over the mode line.\n\ -This variable takes effect when you create a new frame\n\ -or when you set the mouse color."); + doc: /* The shape of the pointer when over the mode line. +This variable takes effect when you create a new frame +or when you set the mouse color. */); #endif Vx_mode_pointer_shape = Qnil; DEFVAR_LISP ("x-sensitive-text-pointer-shape", &Vx_sensitive_text_pointer_shape, - "The shape of the pointer when over mouse-sensitive text.\n\ -This variable takes effect when you create a new frame\n\ -or when you set the mouse color."); + doc: /* The shape of the pointer when over mouse-sensitive text. +This variable takes effect when you create a new frame +or when you set the mouse color. */); Vx_sensitive_text_pointer_shape = Qnil; + DEFVAR_LISP ("x-window-horizontal-drag-cursor", + &Vx_window_horizontal_drag_shape, + doc: /* Pointer shape to use for indicating a window can be dragged horizontally. +This variable takes effect when you create a new frame +or when you set the mouse color. */); + Vx_window_horizontal_drag_shape = Qnil; + DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel, - "A string indicating the foreground color of the cursor box."); + doc: /* A string indicating the foreground color of the cursor box. */); Vx_cursor_fore_pixel = Qnil; + DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size, + doc: /* Maximum size for tooltips. Value is a pair (COLUMNS . ROWS). +Text larger than this is clipped. */); + Vx_max_tooltip_size = Fcons (make_number (80), make_number (40)); + DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager, - "Non-nil if no X window manager is in use.\n\ -Emacs doesn't try to figure this out; this is always nil\n\ -unless you set it to something else."); + doc: /* Non-nil if no X window manager is in use. +Emacs doesn't try to figure this out; this is always nil +unless you set it to something else. */); /* We don't have any way to find this out, so set it to nil and maybe the user would like to set it to t. */ Vx_no_window_manager = Qnil; DEFVAR_LISP ("x-pixel-size-width-font-regexp", &Vx_pixel_size_width_font_regexp, - "Regexp matching a font name whose width is the same as `PIXEL_SIZE'.\n\ -\n\ -Since Emacs gets width of a font matching with this regexp from\n\ -PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\ -such a font. This is especially effective for such large fonts as\n\ -Chinese, Japanese, and Korean."); + doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. + +Since Emacs gets width of a font matching with this regexp from +PIXEL_SIZE field of the name, font finding mechanism gets faster for +such a font. This is especially effective for such large fonts as +Chinese, Japanese, and Korean. */); Vx_pixel_size_width_font_regexp = Qnil; DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay, - "Time after which cached images are removed from the cache.\n\ -When an image has not been displayed this many seconds, remove it\n\ -from the image cache. Value must be an integer or nil with nil\n\ -meaning don't clear the cache."); + doc: /* Time after which cached images are removed from the cache. +When an image has not been displayed this many seconds, remove it +from the image cache. Value must be an integer or nil with nil +meaning don't clear the cache. */); Vimage_cache_eviction_delay = make_number (30 * 60); #ifdef USE_X_TOOLKIT - Fprovide (intern ("x-toolkit")); -#endif + Fprovide (intern ("x-toolkit"), Qnil); #ifdef USE_MOTIF - Fprovide (intern ("motif")); -#endif + Fprovide (intern ("motif"), Qnil); + + DEFVAR_LISP ("motif-version-string", &Vmotif_version_string, + doc: /* Version info for LessTif/Motif. */); + Vmotif_version_string = build_string (XmVERSION_STRING); +#endif /* USE_MOTIF */ +#endif /* USE_X_TOOLKIT */ defsubr (&Sx_get_resource); @@ -11172,7 +11912,8 @@ meaning don't clear the cache."); defsubr (&Sx_display_list); defsubr (&Sx_synchronize); defsubr (&Sx_focus_frame); - + defsubr (&Sx_backspace_delete_keys_p); + /* Setting callback functions for fontset handler. */ get_font_info_func = x_get_font_info; @@ -11192,8 +11933,8 @@ meaning don't clear the cache."); staticpro (&Qxbm); QCtype = intern (":type"); staticpro (&QCtype); - QCalgorithm = intern (":algorithm"); - staticpro (&QCalgorithm); + QCconversion = intern (":conversion"); + staticpro (&QCconversion); QCheuristic_mask = intern (":heuristic-mask"); staticpro (&QCheuristic_mask); QCcolor_symbols = intern (":color-symbols"); @@ -11248,13 +11989,18 @@ meaning don't clear the cache."); defsubr (&Simage_size); defsubr (&Simage_mask_p); - busy_cursor_atimer = NULL; - busy_cursor_shown_p = 0; + hourglass_atimer = NULL; + hourglass_shown_p = 0; defsubr (&Sx_show_tip); defsubr (&Sx_hide_tip); - staticpro (&tip_timer); tip_timer = Qnil; + staticpro (&tip_timer); + tip_frame = Qnil; + staticpro (&tip_frame); + + last_show_tip_args = Qnil; + staticpro (&last_show_tip_args); #ifdef USE_MOTIF defsubr (&Sx_file_dialog);