X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/9d1af64f7a75e2ab67f08422b5057edecf9b895b..f1d2ce7f2f7067d538ac590df4e9f4f0d2738dab:/src/xfns.c diff --git a/src/xfns.c b/src/xfns.c index 9e7f926884..6e8931b42d 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -124,7 +124,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". */ @@ -149,6 +149,11 @@ Lisp_Object Vx_busy_pointer_shape; 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; @@ -239,7 +244,6 @@ extern Lisp_Object Qdisplay; Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background; Lisp_Object Qscreen_gamma, Qline_spacing, Qcenter; Lisp_Object Qcompound_text; -extern Lisp_Object Qbackground_tile; /* The below are defined in frame.c. */ @@ -251,6 +255,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. */ @@ -664,9 +673,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; @@ -745,13 +751,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)); void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object)); -void x_set_background_tile 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)); void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object)); @@ -798,7 +805,6 @@ static struct x_frame_parm_table x_frame_parms[] = "auto-raise", x_set_autoraise, "auto-lower", x_set_autolower, "background-color", x_set_background_color, - "background-tile", x_set_background_tile, "border-color", x_set_border_color, "border-width", x_set_border_width, "cursor-color", x_set_cursor_color, @@ -1427,49 +1433,13 @@ x_set_background_color (f, arg, oldval) } } -void -x_set_background_tile (f, arg, oldval) - struct frame *f; - Lisp_Object arg, oldval; -{ - int tile_id = lookup_image (f, arg, 0); - struct image *tile_image = IMAGE_FROM_ID (f, tile_id); - Pixmap tile_pixmap = tile_image ? tile_image->pixmap : 0; - - f->output_data.x->background_tile = tile_pixmap; - - if (FRAME_X_WINDOW (f) != 0 && tile_pixmap) - { - BLOCK_INPUT; - /* The main frame area. */ - XSetTile (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc, - f->output_data.x->background_tile); - XSetWindowBackgroundPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - f->output_data.x->background_tile); - { - Lisp_Object bar; - for (bar = FRAME_SCROLL_BARS (f); !NILP (bar); - bar = XSCROLL_BAR (bar)->next) - XSetWindowBackgroundPixmap (FRAME_X_DISPLAY (f), - SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)), - f->output_data.x->background_tile); - } - UNBLOCK_INPUT; - - update_face_from_frame_parameter (f, Qbackground_tile, arg); - - if (FRAME_VISIBLE_P (f)) - redraw_frame (f); - } -} - void x_set_mouse_color (f, arg, oldval) struct frame *f; Lisp_Object arg, oldval; { Cursor cursor, nontext_cursor, mode_cursor, cross_cursor; - Cursor busy_cursor; + Cursor busy_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; @@ -1537,6 +1507,17 @@ x_set_mouse_color (f, arg, oldval) else cross_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_crosshair); + if (!NILP (Vx_window_horizontal_drag_shape)) + { + CHECK_NUMBER (Vx_window_horizontal_drag_shape, 0); + horizontal_drag_cursor + = XCreateFontCursor (FRAME_X_DISPLAY (f), + XINT (Vx_window_horizontal_drag_shape)); + } + else + horizontal_drag_cursor + = XCreateFontCursor (FRAME_X_DISPLAY (f), 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); @@ -1545,11 +1526,10 @@ x_set_mouse_color (f, arg, oldval) XColor fore_color, back_color; fore_color.pixel = f->output_data.x->mouse_pixel; + x_query_color (f, &fore_color); back_color.pixel = mask_color; - XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), - &fore_color); - XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), - &back_color); + x_query_color (f, &back_color); + XRecolorCursor (FRAME_X_DISPLAY (f), cursor, &fore_color, &back_color); XRecolorCursor (FRAME_X_DISPLAY (f), nontext_cursor, @@ -1557,15 +1537,18 @@ x_set_mouse_color (f, arg, oldval) XRecolorCursor (FRAME_X_DISPLAY (f), mode_cursor, &fore_color, &back_color); XRecolorCursor (FRAME_X_DISPLAY (f), cross_cursor, - &fore_color, &back_color); + &fore_color, &back_color); XRecolorCursor (FRAME_X_DISPLAY (f), busy_cursor, &fore_color, &back_color); + XRecolorCursor (FRAME_X_DISPLAY (f), 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) + 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; @@ -1589,6 +1572,11 @@ x_set_mouse_color (f, arg, oldval) XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->cross_cursor); f->output_data.x->cross_cursor = cross_cursor; + if (horizontal_drag_cursor != f->output_data.x->horizontal_drag_cursor + && f->output_data.x->horizontal_drag_cursor != 0) + XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->horizontal_drag_cursor); + f->output_data.x->horizontal_drag_cursor = horizontal_drag_cursor; + XFlush (FRAME_X_DISPLAY (f)); UNBLOCK_INPUT; @@ -2085,8 +2073,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; + XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + 0, y, width, height, False); + UNBLOCK_INPUT; + } } @@ -2203,6 +2207,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); @@ -3937,20 +3943,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; @@ -3985,6 +3991,74 @@ x_make_gc (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\ @@ -4005,7 +4079,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; @@ -4075,6 +4149,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", @@ -4083,6 +4158,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 @@ -4316,6 +4395,13 @@ This function is an internal primitive--use `make-frame' instead.") 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)) @@ -4364,6 +4450,7 @@ This function is an internal primitive--use `make-frame' instead.") 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. */ @@ -5424,7 +5511,7 @@ or omitted means use the selected frame.") if (valid_image_p (spec)) { struct frame *f = check_x_frame (frame); - int id = lookup_image (f, spec, 0); + 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; @@ -5455,7 +5542,7 @@ or omitted means use the selected frame.") if (valid_image_p (spec)) { struct frame *f = check_x_frame (frame); - int id = lookup_image (f, spec, 0); + int id = lookup_image (f, spec); struct image *img = IMAGE_FROM_ID (f, id); if (img->mask) mask = Qt; @@ -5738,7 +5825,7 @@ clear_image_cache (f, force_p) { struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - if (c && (c->refcount <= 1) && INTEGERP (Vimage_cache_eviction_delay)) + if (c && INTEGERP (Vimage_cache_eviction_delay)) { EMACS_TIME t; unsigned long old; @@ -5775,10 +5862,7 @@ clear_image_cache (f, force_p) struct frame *f = XFRAME (frame); if (FRAME_X_P (f) && FRAME_X_IMAGE_CACHE (f) == c) - { - clear_current_matrices (f); - free_all_realized_faces (frame); - } + clear_current_matrices (f); } ++windows_or_buffers_changed; @@ -5813,15 +5897,12 @@ FRAME t means clear the image caches of all frames.") /* Return the id of image with Lisp specification SPEC on frame F. - SPEC must be a valid Lisp image specification (see valid_image_p). - If DELAY_LOAD is true, then the image isn't actually loaded yet (it - will be loaded when prepare_image_for_display is called). */ + SPEC must be a valid Lisp image specification (see valid_image_p). */ int -lookup_image (f, spec, delay_load) +lookup_image (f, spec) struct frame *f; Lisp_Object spec; - int delay_load; { struct image_cache *c = FRAME_X_IMAGE_CACHE (f); struct image *img; @@ -5851,14 +5932,12 @@ lookup_image (f, spec, delay_load) BLOCK_INPUT; img = make_image (spec, hash); cache_image (f, img); - if (! delay_load) - img->load_failed_p = img->type->load (f, img) == 0; - xassert (!interrupt_input_blocked); + img->load_failed_p = img->type->load (f, img) == 0; /* If we can't load the image, and we don't have a width and height, use some arbitrary width and height so that we can draw a rectangle for it. */ - if (img->pixmap == 0) + if (img->load_failed_p) { Lisp_Object value; @@ -6156,7 +6235,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); @@ -7049,13 +7128,8 @@ xpm_lookup_color (f, color_name, color) char *color_name; XColor *color; { - char *s; struct xpm_cached_color *p; - unsigned h = xpm_color_bucket (color_name); - - for (s = color_name; *s; ++s) - h = (h << 2) ^ *s; - h %= XPM_COLOR_CACHE_BUCKETS; + int h = xpm_color_bucket (color_name); for (p = xpm_color_cache[h]; p; p = p->next) if (strcmp (p->name, color_name) == 0) @@ -7450,7 +7524,7 @@ lookup_pixel_color (f, pixel) cmap = FRAME_X_COLORMAP (f); color.pixel = pixel; - XQueryColor (FRAME_X_DISPLAY (f), cmap, &color); + x_query_color (f, &color); rc = x_alloc_nearest_color (f, cmap, &color); if (rc) @@ -7578,8 +7652,7 @@ x_to_xcolors (f, img, rgb_p) p->pixel = XGetPixel (ximg, x, y); if (rgb_p) - XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), - row, img->width); + x_query_colors (f, row, img->width); } XDestroyImage (ximg); @@ -7959,6 +8032,8 @@ enum pbm_keyword_index PBM_ALGORITHM, PBM_HEURISTIC_MASK, PBM_MASK, + PBM_FOREGROUND, + PBM_BACKGROUND, PBM_LAST }; @@ -7975,7 +8050,9 @@ static struct image_keyword pbm_format[PBM_LAST] = {":relief", IMAGE_INTEGER_VALUE, 0}, {":algorithm", 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}, + {":foreground", IMAGE_STRING_VALUE, 0}, + {":background", IMAGE_STRING_VALUE, 0} }; /* Structure describing the image type `pbm'. */ @@ -8164,6 +8241,19 @@ pbm_load (f, img) if (type == PBM_MONO) { int c = 0, g; + struct image_keyword fmt[PBM_LAST]; + unsigned long fg = FRAME_FOREGROUND_PIXEL (f); + unsigned long bg = FRAME_BACKGROUND_PIXEL (f); + + /* Parse the image specification. */ + bcopy (pbm_format, fmt, sizeof fmt); + parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm); + + /* Get foreground and background colors, maybe allocate colors. */ + if (fmt[PBM_FOREGROUND].count) + 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); for (y = 0; y < height; ++y) for (x = 0; x < width; ++x) @@ -8178,9 +8268,7 @@ pbm_load (f, img) else g = pbm_scan_number (&p, end); - XPutPixel (ximg, x, y, (g - ? FRAME_FOREGROUND_PIXEL (f) - : FRAME_BACKGROUND_PIXEL (f))); + XPutPixel (ximg, x, y, g ? fg : bg); } } else @@ -8578,7 +8666,7 @@ png_load (f, img) cmap = FRAME_X_COLORMAP (f); color.pixel = FRAME_BACKGROUND_PIXEL (f); - XQueryColor (FRAME_X_DISPLAY (f), cmap, &color); + x_query_color (f, &color); bzero (&frame_background, sizeof frame_background); frame_background.red = color.red; @@ -10180,31 +10268,41 @@ show_busy_cursor (timer) 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->busy_p = 1; - if (!f->output_data.x->busy_window) - { - unsigned long mask = CWCursor; - XSetWindowAttributes attrs; + if (!f->output_data.x->busy_window) + { + unsigned long mask = CWCursor; + XSetWindowAttributes attrs; - attrs.cursor = f->output_data.x->busy_cursor; + attrs.cursor = f->output_data.x->busy_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->busy_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->busy_window); + XFlush (dpy); + } + } + } busy_cursor_shown_p = 1; UNBLOCK_INPUT; @@ -10252,9 +10350,9 @@ hide_busy_cursor () static Lisp_Object x_create_tip_frame P_ ((struct x_display_info *, Lisp_Object)); -/* 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. */ @@ -10262,8 +10360,31 @@ struct frame *tip_frame; Lisp_Object tip_timer; Window tip_window; + +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. 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) @@ -10275,7 +10396,7 @@ x_create_tip_frame (dpyinfo, parms) 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; @@ -10301,10 +10422,15 @@ 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); 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)); @@ -10314,6 +10440,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 @@ -10358,8 +10488,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; @@ -10463,7 +10593,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). */ @@ -10511,11 +10644,13 @@ x_create_tip_frame (dpyinfo, parms) below. And the frame needs to be on Vframe_list or making it visible won't work. */ Vframe_list = Fcons (frame, Vframe_list); + tip_frame = frame; /* Now that the frame is official, it counts as a reference to its display. */ FRAME_X_DISPLAY_INFO (f)->reference_count++; + /* Discard the unwind_protect. */ return unbind_to (count, frame); } @@ -10538,7 +10673,7 @@ 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; { @@ -10572,7 +10707,7 @@ 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); @@ -10595,7 +10730,7 @@ 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); + 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 @@ -10700,28 +10835,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 (intern ("cancel-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 != None) + { + BLOCK_INPUT; + xlwmenu_redisplay (w); + UNBLOCK_INPUT; + } + } +#endif /* USE_LUCID */ } - return unbind_to (count, deleted_p ? Qt : Qnil); + UNGCPRO; + return unbind_to (count, deleted); } @@ -10912,6 +11072,68 @@ selection dialog's entry field, if MUSTMATCH is non-nil.") #endif /* USE_MOTIF */ + +/*********************************************************************** + 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; + + have_keys = Qnil; + + BLOCK_INPUT; + kb = XkbGetKeyboard (dpy, XkbAllComponentsMask, XkbUseCoreKbd); + if (kb) + { + int delete_keycode = 0, backspace_keycode = 0, i; + + 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; + } + + XkbFreeKeyboard (kb, XkbAllComponentsMask, 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 @@ -11107,6 +11329,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; @@ -11174,7 +11403,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; @@ -11255,8 +11485,10 @@ meaning don't clear the cache."); defsubr (&Sx_show_tip); defsubr (&Sx_hide_tip); - staticpro (&tip_timer); tip_timer = Qnil; + staticpro (&tip_timer); + tip_frame = Qnil; + staticpro (&tip_frame); #ifdef USE_MOTIF defsubr (&Sx_file_dialog);