X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/a31fedb766dcf23f1df3fc8cc639dece5d2ab27e..1783ffa26e0a54c54841cc84d309365cf4dd89d5:/src/xfns.c diff --git a/src/xfns.c b/src/xfns.c index e0e57abc6c..0d71a16fa6 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. @@ -107,6 +107,14 @@ extern XFontStruct *xlwmenu_default_font; extern void free_frame_menubar (); extern double atof (); +#ifdef USE_MOTIF + +/* LessTif/Motif version info. */ + +static Lisp_Object Vmotif_version_string; + +#endif /* USE_MOTIF */ + #endif /* USE_X_TOOLKIT */ #define min(a,b) ((a) < (b) ? (a) : (b)) @@ -124,7 +132,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 +143,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 +182,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 +216,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 +229,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. */ @@ -346,7 +330,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 +374,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 +416,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) { @@ -663,9 +647,6 @@ x_create_bitmap_from_file (f, file) fd = openp (Vx_bitmap_file_path, file, "", &found, 0); if (fd < 0) return -1; - /* XReadBitmapFile won't handle magic file names. */ - if (fd == 0) - return -1; emacs_close (fd); filename = (char *) XSTRING (found)->data; @@ -744,11 +725,14 @@ 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)); @@ -817,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 @@ -1330,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) @@ -1364,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 @@ -1389,34 +1401,33 @@ 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); + Lisp_Object bar; + 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); - { - Lisp_Object 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); - } - UNBLOCK_INPUT; + 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); + + for (bar = FRAME_SCROLL_BARS (f); + !NILP (bar); + bar = XSCROLL_BAR (bar)->next) + { + Window window = SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)); + XSetWindowBackground (dpy, window, bg); + } + UNBLOCK_INPUT; update_face_from_frame_parameter (f, Qbackground_color, arg); if (FRAME_VISIBLE_P (f)) @@ -1429,127 +1440,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)); + 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)); + 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, 0); + 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)); + 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); 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, 0); + 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); @@ -1562,6 +1587,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)) { @@ -1570,13 +1596,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) { @@ -1584,7 +1610,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) @@ -1592,27 +1618,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)) @@ -1820,6 +1844,7 @@ 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); @@ -1837,6 +1862,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); } @@ -2011,6 +2046,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); @@ -2045,8 +2084,24 @@ x_set_tool_bar_lines (f, value, oldval) { updating_frame = f; clear_frame (); + clear_current_matrices (f); updating_frame = NULL; } + + /* If the tool bar gets smaller, the internal border below it + has to be cleared. It was formerly part of the display + of the larger tool bar, and updating windows won't clear it. */ + if (delta < 0) + { + int height = FRAME_INTERNAL_BORDER_WIDTH (f); + int width = PIXEL_WIDTH (f); + int y = nlines * CANON_Y_UNIT (f); + + BLOCK_INPUT; + x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + 0, y, width, height, False); + UNBLOCK_INPUT; + } } @@ -2163,6 +2218,8 @@ x_encode_text (string, coding_system, text_bytes, stringp) coding.mode |= CODING_MODE_LAST_BLOCK; if (coding.type == coding_type_iso2022) coding.flags |= CODING_FLAG_ISO_SAFE; + /* We suppress producing escape sequences for composition. */ + coding.composing = COMPOSITION_DISABLED; bufsize = encoding_buffer_size (&coding, bytes); buf = (unsigned char *) xmalloc (bufsize); encode_coding (&coding, str, buf, bytes, bufsize); @@ -3260,6 +3317,8 @@ best_xim_style (user, xim) /* Create XIC for frame F. */ +static XIMStyle xic_style; + void create_frame_xic (f) struct frame *f; @@ -3267,7 +3326,6 @@ create_frame_xic (f) XIM xim; XIC xic = NULL; XFontSet xfs = NULL; - static XIMStyle xic_style; if (FRAME_XIC (f)) return; @@ -3897,20 +3955,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; @@ -3939,12 +3997,79 @@ 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\ @@ -3965,7 +4090,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; @@ -4035,6 +4160,7 @@ 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; + record_unwind_protect (unwind_create_frame, frame); f->icon_name = x_get_arg (dpyinfo, parms, Qicon_name, "iconName", "Title", @@ -4043,6 +4169,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 @@ -4052,6 +4182,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); @@ -4207,8 +4347,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) @@ -4231,14 +4403,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 @@ -4272,10 +4437,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)) @@ -4321,9 +4494,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. */ @@ -4894,7 +5073,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) @@ -5067,7 +5246,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. */ @@ -5139,11 +5318,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; @@ -5174,8 +5364,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, @@ -5270,6 +5462,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; @@ -5280,6 +5477,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; @@ -5386,8 +5592,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)), @@ -5516,7 +5722,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) @@ -5638,6 +5844,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 @@ -5769,6 +5976,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). */ @@ -5802,6 +6084,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); @@ -5826,7 +6110,6 @@ lookup_image (f, spec) /* Handle image type independent image attributes `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF'. */ Lisp_Object ascent, margin, relief; - Lisp_Object file; ascent = image_spec_value (spec, QCascent, NULL); if (INTEGERP (ascent)) @@ -5836,80 +6119,28 @@ 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) - { - 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)) - { - Lisp_Object tem; - tem = XCDR (algorithm); - if (CONSP (tem)) - x_edge_detection (f, img, - Fplist_get (tem, QCmatrix), - Fplist_get (tem, QCcolor_adjustment)); - } - } + /* 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; @@ -6108,7 +6339,7 @@ x_find_image_file (file) /* Try to find FILE in data-directory, then x-bitmap-file-path. */ fd = openp (search_path, file, "", &file_found, 0); - if (fd < 0) + if (fd == -1) file_found = Qnil; else close (fd); @@ -6199,12 +6430,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} }; @@ -6709,12 +6940,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. */ @@ -6735,10 +6965,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); @@ -6836,9 +7068,9 @@ 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} @@ -7105,7 +7337,7 @@ xpm_load (f, img) struct frame *f; struct image *img; { - int rc, i; + int rc; XpmAttributes attrs; Lisp_Object specified_file, color_symbols; @@ -7206,6 +7438,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); @@ -7464,7 +7698,7 @@ 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; @@ -7919,13 +8153,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'. */ @@ -8123,9 +8357,11 @@ 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) + if (fmt[PBM_BACKGROUND].count + && STRINGP (fmt[PBM_BACKGROUND].value)) bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg); for (y = 0; y < height; ++y) @@ -8246,9 +8482,9 @@ 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} }; @@ -8723,9 +8959,9 @@ 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} }; @@ -9078,9 +9314,9 @@ 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} }; @@ -9401,9 +9637,9 @@ 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} @@ -9619,7 +9855,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; @@ -9714,9 +9950,9 @@ 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} }; @@ -9933,6 +10169,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; } @@ -10047,138 +10289,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; @@ -10189,17 +10442,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; } } @@ -10211,11 +10465,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. */ @@ -10223,22 +10479,54 @@ 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; + + +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 (); @@ -10262,10 +10550,24 @@ 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)); + 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)); @@ -10275,6 +10577,10 @@ x_create_tip_frame (dpyinfo, parms) f->output_data.x->scroll_bar_background_pixel = -1; 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 @@ -10319,8 +10625,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; @@ -10424,7 +10730,10 @@ x_create_tip_frame (dpyinfo, parms) unsigned long mask; BLOCK_INPUT; - mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask; + mask = CWBackPixel | CWOverrideRedirect | CWEventMask; + if (DoesSaveUnders (dpyinfo->screen)) + mask |= CWSaveUnder; + /* Window managers look at the override-redirect flag to determine whether or net to give windows a decoration (Xlib spec, chapter 3.2.8). */ @@ -10464,6 +10773,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; @@ -10477,10 +10806,69 @@ 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\ @@ -10499,22 +10887,20 @@ 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 -5).") +DY added (default is -10).") (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); @@ -10533,13 +10919,50 @@ DY added (default is -5).") CHECK_NUMBER (dx, 5); if (NILP (dy)) - dy = make_number (-5); + dy = make_number (-10); else CHECK_NUMBER (dy, 6); + 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); @@ -10555,8 +10978,8 @@ DY added (default is -5).") /* 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 @@ -10569,12 +10992,8 @@ DY added (default is -5).") 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)); clear_glyph_matrix (w->desired_matrix); clear_glyph_matrix (w->current_matrix); SET_TEXT_POS (pos, BEGV, BEGV_BYTE); @@ -10614,31 +11033,16 @@ DY added (default is -5).") 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); @@ -10647,6 +11051,7 @@ DY added (default is -5).") 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")); @@ -10661,28 +11066,53 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0, Value is t is 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 + redisplay procedure is not called when a tip frame over menu + items is unmapped. Redisplay the menu manually... */ + { + 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 != NULL) + { + BLOCK_INPUT; + xlwmenu_redisplay (w); + UNBLOCK_INPUT; + } + } +#endif /* USE_LUCID */ } - return unbind_to (count, deleted_p ? Qt : Qnil); + UNGCPRO; + return unbind_to (count, deleted); } @@ -10706,6 +11136,21 @@ 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\ @@ -10758,6 +11203,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); @@ -10809,39 +11256,11 @@ 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. */ result = 0; - while (result == 0 || XtAppPending (Xt_app_con)) + while (result == 0) 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;) - { - 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); - } - -#endif /* not HAVE_MOTIF_2_1 */ - /* Get the result. */ if (result == XmCR_OK) { @@ -10874,6 +11293,92 @@ 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, + "Check if both Backspace and Delete keys are on the keyboard of FRAME.\n\ +FRAME nil means use the selected frame.\n\ +Value is t if we know that both keys are present, and are mapped to the\n\ +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 ***********************************************************************/ @@ -10959,6 +11464,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. */ @@ -10993,7 +11502,7 @@ syms_of_xfns () 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\ +Disabled images are those having an `:conversion disabled' property.\n\ A cross is always drawn on black & white displays."); cross_disabled_images = 0; @@ -11038,20 +11547,20 @@ or when you set the mouse color."); #endif Vx_nontext_pointer_shape = Qnil; - DEFVAR_LISP ("x-busy-pointer-shape", &Vx_busy_pointer_shape, + DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_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; + 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, + "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\ + DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay, + "*Seconds to wait before displaying an hourglass pointer.\n\ Value must be an integer or float."); - Vbusy_cursor_delay = make_number (DEFAULT_BUSY_CURSOR_DELAY); + 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, @@ -11068,6 +11577,13 @@ This variable takes effect when you create a new frame\n\ 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, + "Pointer shape to use for indicating a window can be dragged horizontally.\n\ +This variable takes effect when you create a new frame\n\ +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."); Vx_cursor_fore_pixel = Qnil; @@ -11099,10 +11615,15 @@ meaning don't clear the cache."); #ifdef USE_X_TOOLKIT Fprovide (intern ("x-toolkit")); -#endif + #ifdef USE_MOTIF Fprovide (intern ("motif")); -#endif + + DEFVAR_LISP ("motif-version-string", &Vmotif_version_string, + "Version info for LessTif/Motif."); + Vmotif_version_string = build_string (XmVERSION_STRING); +#endif /* USE_MOTIF */ +#endif /* USE_X_TOOLKIT */ defsubr (&Sx_get_resource); @@ -11135,7 +11656,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; @@ -11155,8 +11677,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"); @@ -11211,13 +11733,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);