X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/c27ed90af576892cae147bfe6be1a8b43126102a..1d424b5859841d55ba95a8e3687ee675c1e6eb60:/src/xfns.c diff --git a/src/xfns.c b/src/xfns.c index 8d539472d1..8f03d90c79 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -1,6 +1,6 @@ /* Functions for the X window system. - Copyright (C) 1989, 92, 93, 94, 95, 96, 97, 98, 99, 2000,01,02,03,04 - Free Software Foundation. + Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -16,11 +16,10 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ #include -#include #include #include @@ -151,6 +150,22 @@ char *gray_bitmap_bits = gray_bits; int display_hourglass_p; +/* Non-zero means prompt with the old GTK file selection dialog. */ + +int x_gtk_use_old_file_dialog; + +/* If non-zero, by default show hidden files in the GTK file chooser. */ + +int x_gtk_show_hidden_files; + +/* If non-zero, don't show additional help text in the GTK file chooser. */ + +int x_gtk_file_dialog_help_text; + +/* If non-zero, don't collapse to tool bar when it is detached. */ + +int x_gtk_whole_detached_tool_bar; + /* The background and shape of the mouse pointer, and shape when not over text or in the modeline. */ @@ -566,11 +581,9 @@ x_real_positions (f, xptr, yptr) int had_errors = 0; Window win = f->output_data.x->parent_desc; - int count; - BLOCK_INPUT; - count = x_catch_errors (FRAME_X_DISPLAY (f)); + x_catch_errors (FRAME_X_DISPLAY (f)); if (win == FRAME_X_DISPLAY_INFO (f)->root_window) win = FRAME_OUTER_WINDOW (f); @@ -605,7 +618,7 @@ x_real_positions (f, xptr, yptr) if (! had_errors) { - int ign; + unsigned int ign; Window child, rootw; /* Get the real coordinates for the WM window upper left corner */ @@ -657,7 +670,7 @@ x_real_positions (f, xptr, yptr) had_errors = x_had_errors_p (FRAME_X_DISPLAY (f)); } - x_uncatch_errors (FRAME_X_DISPLAY (f), count); + x_uncatch_errors (); UNBLOCK_INPUT; @@ -750,9 +763,7 @@ x_decode_color (f, color_name, mono_color) if (x_defined_color (f, SDATA (color_name), &cdef, 1)) return cdef.pixel; - Fsignal (Qerror, Fcons (build_string ("Undefined color"), - Fcons (color_name, Qnil))); - return 0; + signal_error ("Undefined color", color_name); } @@ -779,21 +790,16 @@ xg_set_icon (f, file) FRAME_PTR f; Lisp_Object file; { - struct gcpro gcpro1; int result = 0; Lisp_Object found; - GCPRO1 (found); - found = x_find_image_file (file); if (! NILP (found)) { GdkPixbuf *pixbuf; GError *err = NULL; - char *filename; - - filename = SDATA (found); + char *filename = (char *) SDATA (found); BLOCK_INPUT; pixbuf = gdk_pixbuf_new_from_file (filename, &err); @@ -812,9 +818,24 @@ xg_set_icon (f, file) UNBLOCK_INPUT; } - UNGCPRO; return result; } + +int +xg_set_icon_from_xpm_data (f, data) + FRAME_PTR f; + char **data; +{ + int result = 0; + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **) data); + + if (!pixbuf) + return 0; + + gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), pixbuf); + g_object_unref (pixbuf); + return 1; +} #endif /* USE_GTK */ @@ -921,7 +942,6 @@ x_set_mouse_color (f, arg, oldval) Display *dpy = FRAME_X_DISPLAY (f); Cursor cursor, nontext_cursor, mode_cursor, hand_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 = x->background_pixel; @@ -938,7 +958,7 @@ x_set_mouse_color (f, arg, oldval) BLOCK_INPUT; /* It's not okay to crash if the user selects a screwy cursor. */ - count = x_catch_errors (dpy); + x_catch_errors (dpy); if (!NILP (Vx_pointer_shape)) { @@ -999,7 +1019,7 @@ x_set_mouse_color (f, arg, oldval) /* Check and report errors with the above calls. */ x_check_errors (dpy, "can't set cursor shape: %s"); - x_uncatch_errors (dpy, count); + x_uncatch_errors (); { XColor fore_color, back_color; @@ -1231,7 +1251,7 @@ x_set_icon_name (f, arg, oldval) if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt)) return; } - else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil)) + else if (!NILP (arg) || NILP (oldval)) return; f->icon_name = arg; @@ -1394,10 +1414,14 @@ x_set_tool_bar_lines (f, value, oldval) int width = FRAME_PIXEL_WIDTH (f); int y = nlines * FRAME_LINE_HEIGHT (f); - BLOCK_INPUT; - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - 0, y, width, height, False); - UNBLOCK_INPUT; + /* height can be zero here. */ + if (height > 0 && width > 0) + { + BLOCK_INPUT; + x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + 0, y, width, height, False); + UNBLOCK_INPUT; + } if (WINDOWP (f->tool_bar_window)) clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix); @@ -1508,11 +1532,12 @@ x_set_scroll_bar_background (f, value, oldval) Otherwise store 0 in *STRINGP, which means that the `encoding' of the result should be `COMPOUND_TEXT'. */ -unsigned char * -x_encode_text (string, coding_system, selectionp, text_bytes, stringp) +static unsigned char * +x_encode_text (string, coding_system, selectionp, text_bytes, stringp, freep) Lisp_Object string, coding_system; int *text_bytes, *stringp; int selectionp; + int *freep; { unsigned char *str = SDATA (string); int chars = SCHARS (string); @@ -1529,6 +1554,7 @@ x_encode_text (string, coding_system, selectionp, text_bytes, stringp) /* No multibyte character in OBJ. We need not encode it. */ *text_bytes = bytes; *stringp = 1; + *freep = 0; return str; } @@ -1556,6 +1582,7 @@ x_encode_text (string, coding_system, selectionp, text_bytes, stringp) *stringp = (charset_info == 1 || (!EQ (coding_system, Qcompound_text) && !EQ (coding_system, Qcompound_text_with_extensions))); + *freep = 1; return buf; } @@ -1594,17 +1621,14 @@ x_set_name_internal (f, name) in the future which can encode all Unicode characters. But, for the moment, there's no way to know that the current window manager supports it or not. */ - text.value = x_encode_text (name, coding_system, 0, &bytes, &stringp); + text.value = x_encode_text (name, coding_system, 0, &bytes, &stringp, + &do_free_text_value); text.encoding = (stringp ? XA_STRING : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT); text.format = 8; text.nitems = bytes; - /* Check early, because ENCODE_UTF_8 below may GC and name may be - relocated. */ - do_free_text_value = text.value != SDATA (name); - - if (NILP (f->icon_name)) + if (!STRINGP (f->icon_name)) { icon = text; } @@ -1612,17 +1636,16 @@ x_set_name_internal (f, name) { /* See the above comment "Note: Encoding strategy". */ icon.value = x_encode_text (f->icon_name, coding_system, 0, - &bytes, &stringp); + &bytes, &stringp, &do_free_icon_value); icon.encoding = (stringp ? XA_STRING : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT); icon.format = 8; icon.nitems = bytes; - do_free_icon_value = icon.value != SDATA (f->icon_name); } #ifdef USE_GTK gtk_window_set_title (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), - SDATA (ENCODE_UTF_8 (name))); + (char *) SDATA (ENCODE_UTF_8 (name))); #else /* not USE_GTK */ XSetWMName (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), &text); #endif /* not USE_GTK */ @@ -1872,7 +1895,8 @@ hack_wm_protocols (f, widget) BLOCK_INPUT; { - Atom type, *atoms = 0; + Atom type; + unsigned char *catoms; int format = 0; unsigned long nitems = 0; unsigned long bytes_after; @@ -1881,20 +1905,27 @@ hack_wm_protocols (f, widget) FRAME_X_DISPLAY_INFO (f)->Xatom_wm_protocols, (long)0, (long)100, False, XA_ATOM, &type, &format, &nitems, &bytes_after, - (unsigned char **) &atoms) + &catoms) == Success) && format == 32 && type == XA_ATOM) - while (nitems > 0) - { - nitems--; - if (atoms[nitems] == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_delete_window) - need_delete = 0; - else if (atoms[nitems] == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_take_focus) - need_focus = 0; - else if (atoms[nitems] == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_save_yourself) - need_save = 0; - } - if (atoms) XFree ((char *) atoms); + { + Atom *atoms = (Atom *) catoms; + while (nitems > 0) + { + nitems--; + if (atoms[nitems] + == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_delete_window) + need_delete = 0; + else if (atoms[nitems] + == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_take_focus) + need_focus = 0; + else if (atoms[nitems] + == FRAME_X_DISPLAY_INFO (f)->Xatom_wm_save_yourself) + need_save = 0; + } + } + if (catoms) + XFree (catoms); } { Atom props [10]; @@ -1943,23 +1974,156 @@ static XIMStyle supported_xim_styles[] = /* Create an X fontset on frame F with base font name BASE_FONTNAME. */ +char xic_defaut_fontset[] = "-*-*-*-r-normal--14-*-*-*-*-*-*-*"; + +/* Create an Xt fontset spec from the name of a base font. + If `motif' is True use the Motif syntax. */ +char * +xic_create_fontsetname (base_fontname, motif) + char *base_fontname; + Bool motif; +{ + const char *sep = motif ? ";" : ","; + char *fontsetname; + + /* Make a fontset name from the base font name. */ + if (xic_defaut_fontset == base_fontname) + { /* There is no base font name, use the default. */ + int len = strlen (base_fontname) + 2; + fontsetname = xmalloc (len); + bzero (fontsetname, len); + strcpy (fontsetname, base_fontname); + } + else + { + /* Make a fontset name from the base font name. + The font set will be made of the following elements: + - the base font. + - the base font where the charset spec is replaced by -*-*. + - the same but with the family also replaced with -*-*-. */ + char *p = base_fontname; + int i; + + for (i = 0; *p; p++) + if (*p == '-') i++; + if (i != 14) + { /* As the font name doesn't conform to XLFD, we can't + modify it to generalize it to allcs and allfamilies. + Use the specified font plus the default. */ + int len = strlen (base_fontname) + strlen (xic_defaut_fontset) + 3; + fontsetname = xmalloc (len); + bzero (fontsetname, len); + strcpy (fontsetname, base_fontname); + strcat (fontsetname, sep); + strcat (fontsetname, xic_defaut_fontset); + } + else + { + int len; + char *p1 = NULL, *p2 = NULL, *p3 = NULL; + char *font_allcs = NULL; + char *font_allfamilies = NULL; + char *font_all = NULL; + char *allcs = "*-*-*-*-*-*-*"; + char *allfamilies = "-*-*-"; + char *all = "*-*-*-*-"; + char *base; + + for (i = 0, p = base_fontname; i < 8; p++) + { + if (*p == '-') + { + i++; + if (i == 3) + p1 = p + 1; + else if (i == 7) + p2 = p + 1; + else if (i == 6) + p3 = p + 1; + } + } + /* If base_fontname specifies ADSTYLE, make it a + wildcard. */ + if (*p3 != '*') + { + int diff = (p2 - p3) - 2; + + base = alloca (strlen (base_fontname) + 1); + bcopy (base_fontname, base, p3 - base_fontname); + base[p3 - base_fontname] = '*'; + base[(p3 - base_fontname) + 1] = '-'; + strcpy (base + (p3 - base_fontname) + 2, p2); + p = base + (p - base_fontname) - diff; + p1 = base + (p1 - base_fontname); + p2 = base + (p2 - base_fontname) - diff; + base_fontname = base; + } + + /* Build the font spec that matches all charsets. */ + len = p - base_fontname + strlen (allcs) + 1; + font_allcs = (char *) alloca (len); + bzero (font_allcs, len); + bcopy (base_fontname, font_allcs, p - base_fontname); + strcat (font_allcs, allcs); + + /* Build the font spec that matches all families and + add-styles. */ + len = p - p1 + strlen (allcs) + strlen (allfamilies) + 1; + font_allfamilies = (char *) alloca (len); + bzero (font_allfamilies, len); + strcpy (font_allfamilies, allfamilies); + bcopy (p1, font_allfamilies + strlen (allfamilies), p - p1); + strcat (font_allfamilies, allcs); + + /* Build the font spec that matches all. */ + len = p - p2 + strlen (allcs) + strlen (all) + strlen (allfamilies) + 1; + font_all = (char *) alloca (len); + bzero (font_all, len); + strcpy (font_all, allfamilies); + strcat (font_all, all); + bcopy (p2, font_all + strlen (all) + strlen (allfamilies), p - p2); + strcat (font_all, allcs); + + /* Build the actual font set name. */ + len = strlen (base_fontname) + strlen (font_allcs) + + strlen (font_allfamilies) + strlen (font_all) + 5; + fontsetname = xmalloc (len); + bzero (fontsetname, len); + strcpy (fontsetname, base_fontname); + strcat (fontsetname, sep); + strcat (fontsetname, font_allcs); + strcat (fontsetname, sep); + strcat (fontsetname, font_allfamilies); + strcat (fontsetname, sep); + strcat (fontsetname, font_all); + } + } + if (motif) + strcat (fontsetname, ":"); + return fontsetname; +} + static XFontSet xic_create_xfontset (f, base_fontname) struct frame *f; char *base_fontname; { XFontSet xfs = NULL; - char **missing_list; + char **missing_list = NULL; int missing_count; char *def_string; Lisp_Object rest, frame; + if (!base_fontname) + base_fontname = xic_defaut_fontset; + /* See if there is another frame already using same fontset. */ FOR_EACH_FRAME (rest, frame) { struct frame *cf = XFRAME (frame); if (cf != f && FRAME_LIVE_P (f) && FRAME_X_P (cf) && FRAME_X_DISPLAY_INFO (cf) == FRAME_X_DISPLAY_INFO (f) + && FRAME_XIC_BASE_FONTNAME (cf) && !strcmp (FRAME_XIC_BASE_FONTNAME (cf), base_fontname)) { xfs = FRAME_XIC_FONTSET (cf); @@ -1968,12 +2132,40 @@ xic_create_xfontset (f, base_fontname) } if (!xfs) - /* New fontset. */ - xfs = XCreateFontSet (FRAME_X_DISPLAY (f), - base_fontname, &missing_list, - &missing_count, &def_string); - if (missing_list) - XFreeStringList (missing_list); + { + char *fontsetname = xic_create_fontsetname (base_fontname, False); + + /* New fontset. */ + xfs = XCreateFontSet (FRAME_X_DISPLAY (f), + fontsetname, &missing_list, + &missing_count, &def_string); + if (missing_list) + XFreeStringList (missing_list); + if (! xfs) + { + /* FONTSETNAME contains a list of font names (specific fonts + first, general fonts last), but giving that to + XCreateFontSet at once occasionally fails (bug of X?). + So, we try to call XCreateFontSet for each fontname. */ + char *p0 = fontsetname, *p1; + + while (p0) + { + p1 = strchr (p0, ','); + if (p1) + *p1 = '\0'; + xfs = XCreateFontSet (FRAME_X_DISPLAY (f), + p0, &missing_list, + &missing_count, &def_string); + if (missing_list) + XFreeStringList (missing_list); + if (xfs) + break; + p0 = p1 ? p1 + 1 : NULL; + } + } + xfree (fontsetname); + } if (FRAME_XIC_BASE_FONTNAME (f)) xfree (FRAME_XIC_BASE_FONTNAME (f)); @@ -2054,6 +2246,11 @@ create_frame_xic (f) if (FRAME_XIC (f)) return; + /* Create X fontset. */ + xfs = xic_create_xfontset + (f, (FRAME_FONTSET (f) < 0) ? NULL + : (char *) SDATA (fontset_ascii (FRAME_FONTSET (f)))); + xim = FRAME_X_XIM (f); if (xim) { @@ -2061,52 +2258,9 @@ create_frame_xic (f) XPoint spot; XVaNestedList preedit_attr; XVaNestedList status_attr; - char *base_fontname; - int fontset; s_area.x = 0; s_area.y = 0; s_area.width = 1; s_area.height = 1; spot.x = 0; spot.y = 1; - /* Create X fontset. */ - fontset = FRAME_FONTSET (f); - if (fontset < 0) - base_fontname = "-*-*-*-r-normal--14-*-*-*-*-*-*-*"; - else - { - /* Determine the base fontname from the ASCII font name of - FONTSET. */ - char *ascii_font = (char *) SDATA (fontset_ascii (fontset)); - char *p = ascii_font; - int i; - - for (i = 0; *p; p++) - if (*p == '-') i++; - if (i != 14) - /* As the font name doesn't conform to XLFD, we can't - modify it to get a suitable base fontname for the - frame. */ - base_fontname = "-*-*-*-r-normal--14-*-*-*-*-*-*-*"; - else - { - int len = strlen (ascii_font) + 1; - char *p1 = NULL; - - for (i = 0, p = ascii_font; i < 8; p++) - { - if (*p == '-') - { - i++; - if (i == 3) - p1 = p + 1; - } - } - base_fontname = (char *) alloca (len); - bzero (base_fontname, len); - strcpy (base_fontname, "-*-*-"); - bcopy (p1, base_fontname + 5, p - p1); - strcat (base_fontname, "*-*-*-*-*-*-*"); - } - } - xfs = xic_create_xfontset (f, base_fontname); /* Determine XIC style. */ if (xic_style == 0) @@ -2709,12 +2863,15 @@ x_icon (f, parms) if (! EQ (icon_x, Qunbound)) x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y)); +#if 0 /* x_get_arg removes the visibility parameter as a side effect, + but x_create_frame still needs it. */ /* Start up iconic or window? */ x_wm_set_window_state (f, (EQ (x_get_arg (dpyinfo, parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon) ? IconicState : NormalState)); +#endif x_text_icon (f, (char *) SDATA ((!NILP (f->icon_name) ? f->icon_name @@ -2856,9 +3013,11 @@ unwind_create_frame (frame) x_free_frame_resources (f); +#if GLYPH_DEBUG /* Check that reference counts are indeed correct. */ xassert (dpyinfo->reference_count == dpyinfo_refcount); xassert (dpyinfo->image_cache->refcount == image_cache_refcount); +#endif return Qt; } @@ -2895,6 +3054,8 @@ This function is an internal primitive--use `make-frame' instead. */) check_x (); + parms = Fcopy_alist (parms); + /* Use this general default value to start with until we know if this frame has a specified name. */ Vx_resource_name = Vinvocation_name; @@ -2960,7 +3121,6 @@ This function is an internal primitive--use `make-frame' instead. */) f->output_data.x->scroll_bar_top_shadow_pixel = -1; f->output_data.x->scroll_bar_bottom_shadow_pixel = -1; #endif /* USE_TOOLKIT_SCROLL_BARS */ - record_unwind_protect (unwind_create_frame, frame); f->icon_name = x_get_arg (dpyinfo, parms, Qicon_name, "iconName", "Title", @@ -2969,6 +3129,9 @@ This function is an internal primitive--use `make-frame' instead. */) f->icon_name = Qnil; FRAME_X_DISPLAY_INFO (f) = dpyinfo; + + /* With FRAME_X_DISPLAY_INFO set up, this unwind-protect is safe. */ + record_unwind_protect (unwind_create_frame, frame); #if GLYPH_DEBUG image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount; dpyinfo_refcount = dpyinfo->reference_count; @@ -3074,8 +3237,7 @@ This function is an internal primitive--use `make-frame' instead. */) if (! STRINGP (font)) font = build_string ("fixed"); - x_default_parameter (f, parms, Qfont, font, - "font", "Font", RES_TYPE_STRING); + x_set_frame_parameters (f, Fcons (Fcons (Qfont, font), Qnil)); } #ifdef USE_LUCID @@ -3182,7 +3344,7 @@ This function is an internal primitive--use `make-frame' instead. */) /* We need to do this after creating the X window, so that the icon-creation functions can say whose icon they're describing. */ - x_default_parameter (f, parms, Qicon_type, Qnil, + x_default_parameter (f, parms, Qicon_type, Qt, "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL); x_default_parameter (f, parms, Qauto_raise, Qnil, @@ -3260,10 +3422,23 @@ This function is an internal primitive--use `make-frame' instead. */) FRAME_OUTER_WINDOW (f), dpyinfo->Xatom_wm_client_leader, XA_WINDOW, 32, PropModeReplace, - (char *) &dpyinfo->client_leader_window, 1); + (unsigned char *) &dpyinfo->client_leader_window, 1); UNBLOCK_INPUT; } + /* Initialize `default-minibuffer-frame' in case this is the first + frame on this display device. */ + if (FRAME_HAS_MINIBUF_P (f) + && (!FRAMEP (kb->Vdefault_minibuffer_frame) + || !FRAME_LIVE_P (XFRAME (kb->Vdefault_minibuffer_frame)))) + kb->Vdefault_minibuffer_frame = frame; + + /* All remaining specified parameters, which have not been "used" + by x_get_arg and friends, now go in the misc. alist of the frame. */ + for (tem = parms; !NILP (tem); tem = XCDR (tem)) + if (CONSP (XCAR (tem)) && !NILP (XCAR (XCAR (tem)))) + f->param_alist = Fcons (XCAR (tem), f->param_alist); + UNGCPRO; /* Make sure windows on this frame appear in calls to next-window @@ -3309,13 +3484,12 @@ FRAME nil means use the selected frame. */) { struct frame *f = check_x_frame (frame); Display *dpy = FRAME_X_DISPLAY (f); - int count; BLOCK_INPUT; - count = x_catch_errors (dpy); + x_catch_errors (dpy); XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), RevertToParent, CurrentTime); - x_uncatch_errors (dpy, count); + x_uncatch_errors (); UNBLOCK_INPUT; return Qnil; @@ -3349,14 +3523,9 @@ DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0, CHECK_STRING (color); if (x_defined_color (f, SDATA (color), &foo, 0)) - { - Lisp_Object rgb[3]; - - rgb[0] = make_number (foo.red); - rgb[1] = make_number (foo.green); - rgb[2] = make_number (foo.blue); - return Flist (3, rgb); - } + return list3 (make_number (foo.red), + make_number (foo.green), + make_number (foo.blue)); else return Qnil; } @@ -3496,7 +3665,9 @@ If omitted or nil, that stands for the selected frame's display. */) } DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0, - doc: /* Returns the vendor ID string of the X server of display DISPLAY. + doc: /* Returns the "vendor ID" string of the X server of display DISPLAY. +\(Labelling every distributor as a "vendor" embodies the false assumption +that operating systems cannot be developed and distributed noncommercially.) The optional argument DISPLAY specifies which display to ask about. DISPLAY should be either a frame or a display name (a string). If omitted or nil, that stands for the selected frame's display. */) @@ -3513,7 +3684,7 @@ If omitted or nil, that stands for the selected frame's display. */) DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0, doc: /* Returns the version numbers of the X server of display DISPLAY. The value is a list of three integers: the major and minor -version numbers of the X Protocol in use, and the vendor-specific release +version numbers of the X Protocol in use, and the distributor-specific release number. See also the function `x-server-vendor'. The optional argument DISPLAY specifies which display to ask about. @@ -3944,11 +4115,15 @@ If DISPLAY is nil, that stands for the selected frame's display. */) x_destroy_all_bitmaps (dpyinfo); XSetCloseDownMode (dpyinfo->display, DestroyAll); +#ifdef USE_GTK + xg_display_close (dpyinfo->display); +#else #ifdef USE_X_TOOLKIT XtCloseDisplay (dpyinfo->display); #else XCloseDisplay (dpyinfo->display); #endif +#endif /* ! USE_GTK */ x_delete_display (dpyinfo); UNBLOCK_INPUT; @@ -4056,8 +4231,13 @@ Value is VALUE. */) data = (unsigned char *) xmalloc (nelements); else if (element_format == 16) data = (unsigned char *) xmalloc (nelements*2); - else - data = (unsigned char *) xmalloc (nelements*4); + else /* format == 32 */ + /* The man page for XChangeProperty: + "If the specified format is 32, the property data must be a + long array." + This applies even if long is more than 64 bits. The X library + converts to 32 bits before sending to the X server. */ + data = (unsigned char *) xmalloc (nelements * sizeof(long)); x_fill_property_data (FRAME_X_DISPLAY (f), value, data, element_format); } @@ -4078,7 +4258,7 @@ Value is VALUE. */) if (! NILP (outer_p)) w = FRAME_OUTER_WINDOW (f); else w = FRAME_X_WINDOW (f); - + XChangeProperty (FRAME_X_DISPLAY (f), w, prop_atom, target_type, element_format, PropModeReplace, data, nelements); @@ -4136,7 +4316,7 @@ no value of TYPE. */) Atom prop_atom; int rc; Lisp_Object prop_value = Qnil; - char *tmp_data = NULL; + unsigned char *tmp_data = NULL; Atom actual_type; Atom target_type = XA_STRING; int actual_format; @@ -4176,7 +4356,7 @@ no value of TYPE. */) rc = XGetWindowProperty (FRAME_X_DISPLAY (f), target_window, prop_atom, 0, 0, False, target_type, &actual_type, &actual_format, &actual_size, - &bytes_remaining, (unsigned char **) &tmp_data); + &bytes_remaining, &tmp_data); if (rc == Success) { int size = bytes_remaining; @@ -4189,14 +4369,38 @@ no value of TYPE. */) ! NILP (delete_p), target_type, &actual_type, &actual_format, &actual_size, &bytes_remaining, - (unsigned char **) &tmp_data); + &tmp_data); if (rc == Success && tmp_data) { + /* The man page for XGetWindowProperty says: + "If the returned format is 32, the returned data is represented + as a long array and should be cast to that type to obtain the + elements." + This applies even if long is more than 32 bits, the X library + converts from 32 bit elements received from the X server to long + and passes the long array to us. Thus, for that case bcopy can not + be used. We convert to a 32 bit type here, because so much code + assume on that. + + The bytes and offsets passed to XGetWindowProperty refers to the + property and those are indeed in 32 bit quantities if format is + 32. */ + + if (actual_format == 32 && actual_format < BITS_PER_LONG) + { + unsigned long i; + int *idata = (int *) tmp_data; + long *ldata = (long *) tmp_data; + + for (i = 0; i < actual_size; ++i) + idata[i] = (int) ldata[i]; + } + if (NILP (vector_ret_p)) prop_value = make_string (tmp_data, size); else prop_value = x_property_data_to_lisp (f, - (unsigned char *) tmp_data, + tmp_data, actual_type, actual_format, actual_size); @@ -4239,6 +4443,14 @@ static Lisp_Object Vhourglass_delay; static void show_hourglass P_ ((struct atimer *)); static void hide_hourglass P_ ((void)); +/* Return non-zero if houglass timer has been started or hourglass is shown. */ + +int +hourglass_started () +{ + return hourglass_shown_p || hourglass_atimer != NULL; +} + /* Cancel a currently active hourglass timer, and start a new one. */ @@ -4248,6 +4460,10 @@ start_hourglass () EMACS_TIME delay; int secs, usecs = 0; + /* Don't bother for ttys. */ + if (NILP (Vwindow_system)) + return; + cancel_hourglass (); if (INTEGERP (Vhourglass_delay) @@ -4330,11 +4546,15 @@ show_hourglass (timer) { unsigned long mask = CWCursor; XSetWindowAttributes attrs; - +#ifdef USE_GTK + Window parent = FRAME_X_WINDOW (f); +#else + Window parent = FRAME_OUTER_WINDOW (f); +#endif attrs.cursor = f->output_data.x->hourglass_cursor; f->output_data.x->hourglass_window - = XCreateWindow (dpy, FRAME_OUTER_WINDOW (f), + = XCreateWindow (dpy, parent, 0, 0, 32000, 32000, 0, 0, InputOnly, CopyFromParent, @@ -4462,9 +4682,7 @@ x_create_tip_frame (dpyinfo, parms, text) check_x (); - /* Use this general default value to start with until we know if - this frame has a specified name. */ - Vx_resource_name = Vinvocation_name; + parms = Fcopy_alist (parms); #ifdef MULTI_KBOARD kb = dpyinfo->kboard; @@ -4478,7 +4696,6 @@ x_create_tip_frame (dpyinfo, parms, text) && !EQ (name, Qunbound) && !NILP (name)) error ("Invalid frame name--not a string or nil"); - Vx_resource_name = name; frame = Qnil; GCPRO3 (parms, name, frame); @@ -4781,16 +4998,22 @@ compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y) if (INTEGERP (top)) *root_y = XINT (top); - else if (*root_y + XINT (dy) - height < 0) - *root_y -= XINT (dy); - else - { - *root_y -= height; + else if (*root_y + XINT (dy) <= 0) + *root_y = 0; /* Can happen for negative dy */ + else if (*root_y + XINT (dy) + height <= FRAME_X_DISPLAY_INFO (f)->height) + /* It fits below the pointer */ *root_y += XINT (dy); - } + else if (height + XINT (dy) <= *root_y) + /* It fits above the pointer. */ + *root_y -= height + XINT (dy); + else + /* Put it on the top. */ + *root_y = 0; if (INTEGERP (left)) *root_x = XINT (left); + else if (*root_x + XINT (dx) <= 0) + *root_x = 0; /* Can happen for negative dx */ else if (*root_x + XINT (dx) + width <= FRAME_X_DISPLAY_INFO (f)->width) /* It fits to the right of the pointer. */ *root_x += XINT (dx); @@ -4947,7 +5170,7 @@ Text larger than the specified size is clipped. */) clear_glyph_matrix (w->desired_matrix); clear_glyph_matrix (w->current_matrix); SET_TEXT_POS (pos, BEGV, BEGV_BYTE); - try_window (FRAME_ROOT_WINDOW (f), pos); + try_window (FRAME_ROOT_WINDOW (f), pos, 0); /* Compute width and height of the tooltip. */ width = height = 0; @@ -5071,8 +5294,27 @@ Value is t if tooltip was open, nil otherwise. */) File selection dialog ***********************************************************************/ -#ifdef USE_MOTIF +DEFUN ("x-uses-old-gtk-dialog", Fx_uses_old_gtk_dialog, + Sx_uses_old_gtk_dialog, + 0, 0, 0, + doc: /* Return t if the old Gtk+ file selection dialog is used. */) + () +{ +#ifdef USE_GTK + extern int use_dialog_box; + extern int use_file_dialog; + + if (use_dialog_box + && use_file_dialog + && have_menus_p () + && xg_uses_old_file_dialog ()) + return Qt; +#endif + return Qnil; +} + +#ifdef USE_MOTIF /* Callback for "OK" and "Cancel" on file selection dialog. */ static void @@ -5100,28 +5342,51 @@ file_dialog_unmap_cb (widget, client_data, call_data) *result = XmCR_CANCEL; } +static Lisp_Object +clean_up_file_dialog (arg) + Lisp_Object arg; +{ + struct Lisp_Save_Value *p = XSAVE_VALUE (arg); + Widget dialog = (Widget) p->pointer; + + /* Clean up. */ + BLOCK_INPUT; + XtUnmanageChild (dialog); + XtDestroyWidget (dialog); + x_menu_set_in_use (0); + UNBLOCK_INPUT; + + return Qnil; +} + -DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0, +DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0, doc: /* Read file name, prompting with PROMPT in directory DIR. -Use a file selection dialog. -Select DEFAULT-FILENAME in the dialog's file selection box, if -specified. Don't let the user enter a file name in the file -selection dialog's entry field, if MUSTMATCH is non-nil. */) - (prompt, dir, default_filename, mustmatch) - Lisp_Object prompt, dir, default_filename, mustmatch; +Use a file selection dialog. Select DEFAULT-FILENAME in the dialog's file +selection box, if specified. If MUSTMATCH is non-nil, the returned file +or directory must exist. ONLY-DIR-P is ignored." */) + (prompt, dir, default_filename, mustmatch, only_dir_p) + Lisp_Object prompt, dir, default_filename, mustmatch, only_dir_p; { int result; struct frame *f = SELECTED_FRAME (); Lisp_Object file = Qnil; - Widget dialog, text, list, help; + Lisp_Object decoded_file; + Widget dialog, text, help; Arg al[10]; int ac = 0; extern XtAppContext Xt_app_con; XmString dir_xmstring, pattern_xmstring; int count = SPECPDL_INDEX (); - struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; + struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6; + + check_x (); + + GCPRO6 (prompt, dir, default_filename, mustmatch, only_dir_p, file); + + if (popup_activated ()) + error ("Trying to use a menu from within a menu-entry"); - GCPRO5 (prompt, dir, default_filename, mustmatch, file); CHECK_STRING (prompt); CHECK_STRING (dir); @@ -5154,9 +5419,9 @@ selection dialog's entry field, if MUSTMATCH is non-nil. */) XtAddCallback (dialog, XmNunmapCallback, file_dialog_unmap_cb, (XtPointer) &result); - /* Disable the help button since we can't display help. */ + /* Remove the help button since we can't display help. */ help = XmFileSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON); - XtSetSensitive (help, False); + XtUnmanageChild (help); /* Mark OK button as default. */ XtVaSetValues (XmFileSelectionBoxGetChild (dialog, XmDIALOG_OK_BUTTON), @@ -5178,39 +5443,53 @@ selection dialog's entry field, if MUSTMATCH is non-nil. */) /* Manage the dialog, so that list boxes get filled. */ XtManageChild (dialog); - /* Select DEFAULT_FILENAME in the files list box. DEFAULT_FILENAME - must include the path for this to work. */ - list = XmFileSelectionBoxGetChild (dialog, XmDIALOG_LIST); if (STRINGP (default_filename)) { XmString default_xmstring; - int item_pos; + Widget wtext = XmFileSelectionBoxGetChild (dialog, XmDIALOG_TEXT); + Widget list = XmFileSelectionBoxGetChild (dialog, XmDIALOG_LIST); - default_xmstring - = XmStringCreateLocalized (SDATA (default_filename)); + XmTextPosition last_pos = XmTextFieldGetLastPosition (wtext); + XmTextFieldReplace (wtext, 0, last_pos, + (SDATA (Ffile_name_nondirectory (default_filename)))); - if (!XmListItemExists (list, default_xmstring)) - { - /* Add a new item if DEFAULT_FILENAME is not in the list. */ - XmListAddItem (list, default_xmstring, 0); - item_pos = 0; - } - else - item_pos = XmListItemPos (list, default_xmstring); - XmStringFree (default_xmstring); + /* Select DEFAULT_FILENAME in the files list box. DEFAULT_FILENAME + must include the path for this to work. */ + + default_xmstring = XmStringCreateLocalized (SDATA (default_filename)); + + if (XmListItemExists (list, default_xmstring)) + { + int item_pos = XmListItemPos (list, default_xmstring); + /* Select the item and scroll it into view. */ + XmListSelectPos (list, item_pos, True); + XmListSetPos (list, item_pos); + } - /* Select the item and scroll it into view. */ - XmListSelectPos (list, item_pos, True); - XmListSetPos (list, item_pos); + XmStringFree (default_xmstring); } + record_unwind_protect (clean_up_file_dialog, make_save_value (dialog, 0)); + /* Process events until the user presses Cancel or OK. */ + x_menu_set_in_use (1); result = 0; while (result == 0) { XEvent event; + x_menu_wait_for_event (0); XtAppNextEvent (Xt_app_con, &event); - (void) x_dispatch_event (&event, FRAME_X_DISPLAY (f) ); + if (event.type == KeyPress + && FRAME_X_DISPLAY (f) == event.xkey.display) + { + KeySym keysym = XLookupKeysym (&event.xkey, 0); + + /* Pop down on C-g. */ + if (keysym == XK_g && (event.xkey.state & ControlMask) != 0) + XtUnmanageChild (dialog); + } + + (void) x_dispatch_event (&event, FRAME_X_DISPLAY (f)); } /* Get the result. */ @@ -5228,9 +5507,6 @@ selection dialog's entry field, if MUSTMATCH is non-nil. */) else file = Qnil; - /* Clean up. */ - XtUnmanageChild (dialog); - XtDestroyWidget (dialog); UNBLOCK_INPUT; UNGCPRO; @@ -5238,35 +5514,54 @@ selection dialog's entry field, if MUSTMATCH is non-nil. */) if (NILP (file)) Fsignal (Qquit, Qnil); - return unbind_to (count, file); + decoded_file = DECODE_FILE (file); + + return unbind_to (count, decoded_file); } #endif /* USE_MOTIF */ #ifdef USE_GTK -DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0, - "Read file name, prompting with PROMPT in directory DIR.\n\ -Use a file selection dialog.\n\ -Select DEFAULT-FILENAME in the dialog's file selection box, if\n\ -specified. Don't let the user enter a file name in the file\n\ -selection dialog's entry field, if MUSTMATCH is non-nil.") - (prompt, dir, default_filename, mustmatch) - Lisp_Object prompt, dir, default_filename, mustmatch; +static Lisp_Object +clean_up_dialog (arg) + Lisp_Object arg; +{ + x_menu_set_in_use (0); + + return Qnil; +} + +DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0, + doc: /* Read file name, prompting with PROMPT in directory DIR. +Use a file selection dialog. Select DEFAULT-FILENAME in the dialog's file +selection box, if specified. If MUSTMATCH is non-nil, the returned file +or directory must exist. If ONLY-DIR-P is non-nil, the user can only select +directories. */) + (prompt, dir, default_filename, mustmatch, only_dir_p) + Lisp_Object prompt, dir, default_filename, mustmatch, only_dir_p; { FRAME_PTR f = SELECTED_FRAME (); char *fn; Lisp_Object file = Qnil; - int count = specpdl_ptr - specpdl; - struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; + Lisp_Object decoded_file; + int count = SPECPDL_INDEX (); + struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6; char *cdef_file; - GCPRO5 (prompt, dir, default_filename, mustmatch, file); + check_x (); + + GCPRO6 (prompt, dir, default_filename, mustmatch, only_dir_p, file); + + if (popup_activated ()) + error ("Trying to use a menu from within a menu-entry"); + CHECK_STRING (prompt); CHECK_STRING (dir); /* Prevent redisplay. */ specbind (Qinhibit_redisplay, Qt); + record_unwind_protect (clean_up_dialog, Qnil); BLOCK_INPUT; @@ -5275,7 +5570,9 @@ selection dialog's entry field, if MUSTMATCH is non-nil.") else cdef_file = SDATA (dir); - fn = xg_get_file_name (f, SDATA (prompt), cdef_file, ! NILP (mustmatch)); + fn = xg_get_file_name (f, SDATA (prompt), cdef_file, + ! NILP (mustmatch), + ! NILP (only_dir_p)); if (fn) { @@ -5290,7 +5587,9 @@ selection dialog's entry field, if MUSTMATCH is non-nil.") if (NILP (file)) Fsignal (Qquit, Qnil); - return unbind_to (count, file); + decoded_file = DECODE_FILE (file); + + return unbind_to (count, decoded_file); } #endif /* USE_GTK */ @@ -5310,7 +5609,8 @@ DEFUN ("x-backspace-delete-keys-p", Fx_backspace_delete_keys_p, doc: /* Check if both Backspace and Delete keys are on the keyboard of FRAME. FRAME nil means use the selected frame. Value is t if we know that both keys are present, and are mapped to the -usual X keysyms. */) +usual X keysyms. Value is `lambda' if we cannot determine if both keys are +present and mapped to the usual X keysyms. */) (frame) Lisp_Object frame; { @@ -5329,7 +5629,7 @@ usual X keysyms. */) if (!XkbLibraryVersion (&major, &minor)) { UNBLOCK_INPUT; - return Qnil; + return Qlambda; } /* Check that the server supports XKB. */ @@ -5338,9 +5638,25 @@ usual X keysyms. */) if (!XkbQueryExtension (dpy, &op, &event, &error, &major, &minor)) { UNBLOCK_INPUT; - return Qnil; + return Qlambda; } + /* In this code we check that the keyboard has physical keys with names + that start with BKSP (Backspace) and DELE (Delete), and that they + generate keysym XK_BackSpace and XK_Delete respectively. + This function is used to test if normal-erase-is-backspace should be + turned on. + An alternative approach would be to just check if XK_BackSpace and + XK_Delete are mapped to any key. But if any of those are mapped to + some non-intuitive key combination (Meta-Shift-Ctrl-whatever) and the + user doesn't know about it, it is better to return false here. + It is more obvious to the user what to do if she/he has two keys + clearly marked with names/symbols and one key does something not + expected (i.e. she/he then tries the other). + The cases where Backspace/Delete is mapped to some other key combination + are rare, and in those cases, normal-erase-is-backspace can be turned on + manually. */ + have_keys = Qnil; kb = XkbGetMap (dpy, XkbAllMapComponentsMask, XkbUseCoreKbd); if (kb) @@ -5377,7 +5693,7 @@ usual X keysyms. */) UNBLOCK_INPUT; return have_keys; #else /* not HAVE_XKBGETKEYBOARD */ - return Qnil; + return Qlambda; #endif /* not HAVE_XKBGETKEYBOARD */ } @@ -5532,6 +5848,34 @@ such a font. This is especially effective for such large fonts as Chinese, Japanese, and Korean. */); Vx_pixel_size_width_font_regexp = Qnil; +/* This is not ifdef:ed, so other builds than GTK can customize it. */ + DEFVAR_BOOL ("x-gtk-use-old-file-dialog", &x_gtk_use_old_file_dialog, + doc: /* *Non-nil means prompt with the old GTK file selection dialog. +If nil or if the file selection dialog is not available, the new GTK file +chooser is used instead. To turn off all file dialogs set the +variable `use-file-dialog'. */); + x_gtk_use_old_file_dialog = 0; + + DEFVAR_BOOL ("x-gtk-show-hidden-files", &x_gtk_show_hidden_files, + doc: /* *If non-nil, the GTK file chooser will by default show hidden files. +Note that this is just the default, there is a toggle button on the file +chooser to show or not show hidden files on a case by case basis. */); + x_gtk_show_hidden_files = 0; + + DEFVAR_BOOL ("x-gtk-file-dialog-help-text", &x_gtk_file_dialog_help_text, + doc: /* *If non-nil, the GTK file chooser will show additional help text. +If more space for files in the file chooser dialog is wanted, set this to nil +to turn the additional text off. */); + x_gtk_file_dialog_help_text = 1; + + DEFVAR_BOOL ("x-gtk-whole-detached-tool-bar", &x_gtk_whole_detached_tool_bar, + doc: /* *If non-nil, a detached tool bar is shown in full. +The default is to just show an arrow and pressing on that arrow shows +the tool bar buttons. */); + x_gtk_whole_detached_tool_bar = 0; + + Fprovide (intern ("x"), Qnil); + #ifdef USE_X_TOOLKIT Fprovide (intern ("x-toolkit"), Qnil); #ifdef USE_MOTIF @@ -5618,6 +5962,7 @@ Chinese, Japanese, and Korean. */); last_show_tip_args = Qnil; staticpro (&last_show_tip_args); + defsubr (&Sx_uses_old_gtk_dialog); #if defined (USE_MOTIF) || defined (USE_GTK) defsubr (&Sx_file_dialog); #endif