diff options
Diffstat (limited to 'src')
388 files changed, 20967 insertions, 20393 deletions
diff --git a/src/.gdbinit b/src/.gdbinit index ca6648e162f..9e4e674c740 100644 --- a/src/.gdbinit +++ b/src/.gdbinit @@ -1,4 +1,4 @@ -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2003 +# Copyright (C) 1992, 93, 94, 95, 96, 97, 1998, 2000, 01, 2004 # Free Software Foundation, Inc. # # This file is part of GNU Emacs. @@ -38,12 +38,22 @@ handle SIGALRM ignore # Set up a mask to use. # This should be EMACS_INT, but in some cases that is a macro. # long ought to work in all cases right now. -set $valmask = ((long)1 << gdb_valbits) - 1 -set $nonvalbits = gdb_emacs_intbits - gdb_valbits + +define xgetptr + set $ptr = (gdb_use_union ? $arg0.u.val : $arg0 & $valmask) | gdb_data_seg_bits +end + +define xgetint + set $int = gdb_use_union ? $arg0.s.val : (gdb_use_lsb ? $arg0 : $arg0 << gdb_gctypebits) >> gdb_gctypebits +end + +define xgettype + set $type = gdb_use_union ? $arg0.s.type : (enum Lisp_Type) (gdb_use_lsb ? $arg0 & $tagmask : $arg0 >> gdb_valbits) +end # Set up something to print out s-expressions. define pr -set debug_print ($) + set debug_print ($) end document pr Print the emacs s-expression which is $. @@ -51,115 +61,135 @@ Works only when an inferior emacs is executing. end define xtype -output (enum Lisp_Type) (($ >> gdb_valbits) & 0x7) -echo \n -output ((($ >> gdb_valbits) & 0x7) == Lisp_Misc ? (enum Lisp_Misc_Type) (((struct Lisp_Free *) (($ & $valmask) | gdb_data_seg_bits))->type) : (($ >> gdb_valbits) & 0x7) == Lisp_Vectorlike ? ($size = ((struct Lisp_Vector *) (($ & $valmask) | gdb_data_seg_bits))->size, (enum pvec_type) (($size & PVEC_FLAG) ? $size & PVEC_TYPE_MASK : 0)) : 0) -echo \n + xgettype $ + output $type + echo \n + if $type == Lisp_Misc + xmisctype + else + if $type == Lisp_Vectorlike + xvectype + end + end end document xtype Print the type of $, assuming it is an Emacs Lisp value. If the first type printed is Lisp_Vector or Lisp_Misc, -the second line gives the more precise type. -Otherwise the second line doesn't mean anything. +a second line gives the more precise type. end define xvectype -set $size = ((struct Lisp_Vector *) (($ & $valmask) | gdb_data_seg_bits))->size -output (enum pvec_type) (($size & PVEC_FLAG) ? $size & PVEC_TYPE_MASK : 0) -echo \n + xgetptr $ + set $size = ((struct Lisp_Vector *) $ptr)->size + output ($size & PVEC_FLAG) ? (enum pvec_type) ($size & PVEC_TYPE_MASK) : $size + echo \n end document xvectype -Print the vector subtype of $, assuming it is a vector or pseudovector. +Print the size or vector subtype of $, assuming it is a vector or pseudovector. end define xmisctype -output (enum Lisp_Misc_Type) (((struct Lisp_Free *) (($ & $valmask) | gdb_data_seg_bits))->type) -echo \n + xgetptr $ + output (enum Lisp_Misc_Type) (((struct Lisp_Free *) $ptr)->type) + echo \n end document xmisctype Print the specific type of $, assuming it is some misc type. end define xint -print (($ & $valmask) << $nonvalbits) >> $nonvalbits + xgetint $ + print $int end document xint Print $, assuming it is an Emacs Lisp integer. This gets the sign right. end define xptr -print (void *) (($ & $valmask) | gdb_data_seg_bits) + xgetptr $ + print (void *) $ptr end document xptr Print the pointer portion of $, assuming it is an Emacs Lisp value. end define xmarker -print (struct Lisp_Marker *) (($ & $valmask) | gdb_data_seg_bits) + xgetptr $ + print (struct Lisp_Marker *) $ptr end document xmarker Print $ as a marker pointer, assuming it is an Emacs Lisp marker value. end define xoverlay -print (struct Lisp_Overlay *) (($ & $valmask) | gdb_data_seg_bits) + xgetptr $ + print (struct Lisp_Overlay *) $ptr end document xoverlay Print $ as a overlay pointer, assuming it is an Emacs Lisp overlay value. end define xmiscfree -print (struct Lisp_Free *) (($ & $valmask) | gdb_data_seg_bits) + xgetptr $ + print (struct Lisp_Free *) $ptr end document xmiscfree Print $ as a misc free-cell pointer, assuming it is an Emacs Lisp Misc value. end define xintfwd -print (struct Lisp_Intfwd *) (($ & $valmask) | gdb_data_seg_bits) + xgetptr $ + print (struct Lisp_Intfwd *) $ptr end document xintfwd Print $ as an integer forwarding pointer, assuming it is an Emacs Lisp Misc value. end define xboolfwd -print (struct Lisp_Boolfwd *) (($ & $valmask) | gdb_data_seg_bits) + xgetptr $ + print (struct Lisp_Boolfwd *) $ptr end document xboolfwd Print $ as a boolean forwarding pointer, assuming it is an Emacs Lisp Misc value. end define xobjfwd -print (struct Lisp_Objfwd *) (($ & $valmask) | gdb_data_seg_bits) + xgetptr $ + print (struct Lisp_Objfwd *) $ptr end document xobjfwd Print $ as an object forwarding pointer, assuming it is an Emacs Lisp Misc value. end define xbufobjfwd -print (struct Lisp_Buffer_Objfwd *) (($ & $valmask) | gdb_data_seg_bits) + xgetptr $ + print (struct Lisp_Buffer_Objfwd *) $ptr end document xbufobjfwd Print $ as a buffer-local object forwarding pointer, assuming it is an Emacs Lisp Misc value. end define xkbobjfwd -print (struct Lisp_Kboard_Objfwd *) (($ & $valmask) | gdb_data_seg_bits) + xgetptr $ + print (struct Lisp_Kboard_Objfwd *) $ptr end document xkbobjfwd Print $ as a kboard-local object forwarding pointer, assuming it is an Emacs Lisp Misc value. end define xbuflocal -print (struct Lisp_Buffer_Local_Value *) (($ & $valmask) | gdb_data_seg_bits) + xgetptr $ + print (struct Lisp_Buffer_Local_Value *) $ptr end document xbuflocal Print $ as a buffer-local-value pointer, assuming it is an Emacs Lisp Misc value. end define xsymbol -print (struct Lisp_Symbol *) ((((int) $) & $valmask) | gdb_data_seg_bits) -xprintsym $ + xgetptr $ + print (struct Lisp_Symbol *) $ptr + xprintsym $ + echo \n end document xsymbol Print the name and address of the symbol $. @@ -167,9 +197,10 @@ This command assumes that $ is an Emacs Lisp symbol value. end define xstring -print (struct Lisp_String *) (($ & $valmask) | gdb_data_seg_bits) -output ($->size > 1000) ? 0 : ($->data[0])@($->size_byte < 0 ? $->size : $->size_byte) -echo \n + xgetptr $ + print (struct Lisp_String *) $ptr + output ($->size > 1000) ? 0 : ($->data[0])@($->size_byte < 0 ? $->size : $->size_byte) + echo \n end document xstring Print the contents and address of the string $. @@ -177,8 +208,9 @@ This command assumes that $ is an Emacs Lisp string value. end define xvector -print (struct Lisp_Vector *) (($ & $valmask) | gdb_data_seg_bits) -output ($->size > 50) ? 0 : ($->contents[0])@($->size) + xgetptr $ + print (struct Lisp_Vector *) $ptr + output ($->size > 50) ? 0 : ($->contents[0])@($->size) echo \n end document xvector @@ -187,32 +219,36 @@ This command assumes that $ is an Emacs Lisp vector value. end define xprocess -print (struct Lisp_Process *) (($ & $valmask) | gdb_data_seg_bits) -output *$ -echo \n + xgetptr $ + print (struct Lisp_Process *) $ptr + output *$ + echo \n end document xprocess Print the address of the struct Lisp_process which the Lisp_Object $ points to. end define xframe -print (struct frame *) (($ & $valmask) | gdb_data_seg_bits) + xgetptr $ + print (struct frame *) $ptr end document xframe Print $ as a frame pointer, assuming it is an Emacs Lisp frame value. end define xcompiled -print (struct Lisp_Vector *) (($ & $valmask) | gdb_data_seg_bits) -output ($->contents[0])@($->size & 0xff) + xgetptr $ + print (struct Lisp_Vector *) $ptr + output ($->contents[0])@($->size & 0xff) end document xcompiled Print $ as a compiled function pointer, assuming it is an Emacs Lisp compiled value. end define xwindow -print (struct window *) (($ & $valmask) | gdb_data_seg_bits) -printf "%dx%d+%d+%d\n", $->width, $->height, $->left, $->top + xgetptr $ + print (struct window *) $ptr + printf "%dx%d+%d+%d\n", $->width, $->height, $->left, $->top end document xwindow Print $ as a window pointer, assuming it is an Emacs Lisp window value. @@ -220,27 +256,30 @@ Print the window's position as "WIDTHxHEIGHT+LEFT+TOP". end define xwinconfig -print (struct save_window_data *) (($ & $valmask) | gdb_data_seg_bits) + xgetptr $ + print (struct save_window_data *) $ptr end document xwinconfig Print $ as a window configuration pointer, assuming it is an Emacs Lisp window configuration value. end define xsubr -print (struct Lisp_Subr *) (($ & $valmask) | gdb_data_seg_bits) -output *$ -echo \n + xgetptr $ + print (struct Lisp_Subr *) $ptr + output *$ + echo \n end document xsubr Print the address of the subr which the Lisp_Object $ points to. end define xchartable -print (struct Lisp_Char_Table *) (($ & $valmask) | gdb_data_seg_bits) -printf " %d extra slots", ($->size & 0x1ff) - 68 -echo \n -printf "Purpose: " -xprintsym $->purpose + xgetptr $ + print (struct Lisp_Char_Table *) $ptr + printf "Purpose: " + xprintsym $->purpose + printf " %d extra slots", ($->size & 0x1ff) - 68 + echo \n end document xchartable Print the address of the char-table $, and its purpose. @@ -248,9 +287,10 @@ This command assumes that $ is an Emacs Lisp char-table value. end define xboolvector -print (struct Lisp_Bool_Vector *) (($ & $valmask) | gdb_data_seg_bits) -output ($->size > 256) ? 0 : ($->data[0])@(($->size + 7)/ 8) -echo \n + xgetptr $ + print (struct Lisp_Bool_Vector *) $ptr + output ($->size > 256) ? 0 : ($->data[0])@(($->size + 7)/ 8) + echo \n end document xboolvector Print the contents and address of the bool-vector $. @@ -258,9 +298,11 @@ This command assumes that $ is an Emacs Lisp bool-vector value. end define xbuffer -print (struct buffer *) (($ & $valmask) | gdb_data_seg_bits) -output ((struct Lisp_String *) ((($->name) & $valmask) | gdb_data_seg_bits))->data -echo \n + xgetptr $ + print (struct buffer *) $ptr + xgetptr $->name + output ((struct Lisp_String *) $ptr)->data + echo \n end document xbuffer Set $ as a buffer pointer, assuming it is an Emacs Lisp buffer value. @@ -268,24 +310,26 @@ Print the name of the buffer. end define xhashtable -print (struct Lisp_Hash_Table *) (($ & $valmask) | gdb_data_seg_bits) + xgetptr $ + print (struct Lisp_Hash_Table *) $ptr end document xhashtable Set $ as a hash table pointer, assuming it is an Emacs Lisp hash table value. end define xcons -print (struct Lisp_Cons *) (($ & $valmask) | gdb_data_seg_bits) -output/x *$ -echo \n + xgetptr $ + print (struct Lisp_Cons *) $ptr + output/x *$ + echo \n end document xcons Print the contents of $, assuming it is an Emacs Lisp cons. end define nextcons -p $.cdr -xcons + p $.cdr + xcons end document nextcons Print the contents of the next cell in a list. @@ -293,28 +337,34 @@ This assumes that the last thing you printed was a cons cell contents (type struct Lisp_Cons) or a pointer to one. end define xcar -print/x ((($ >> gdb_valbits) & 0xf) == Lisp_Cons ? ((struct Lisp_Cons *) (($ & $valmask) | gdb_data_seg_bits))->car : 0) + xgetptr $ + xgettype $ + print/x ($type == Lisp_Cons ? ((struct Lisp_Cons *) $ptr)->car : 0) end document xcar Print the car of $, assuming it is an Emacs Lisp pair. end define xcdr -print/x ((($ >> gdb_valbits) & 0xf) == Lisp_Cons ? ((struct Lisp_Cons *) (($ & $valmask) | gdb_data_seg_bits))->cdr : 0) + xgetptr $ + xgettype $ + print/x ($type == Lisp_Cons ? ((struct Lisp_Cons *) $ptr)->cdr : 0) end document xcdr Print the cdr of $, assuming it is an Emacs Lisp pair. end define xfloat -print ((struct Lisp_Float *) (($ & $valmask) | gdb_data_seg_bits))->data + xgetptr $ + print ((struct Lisp_Float *) $ptr)->data end document xfloat Print $ assuming it is a lisp floating-point number. end define xscrollbar -print (struct scrollbar *) (($ & $valmask) | gdb_data_seg_bits) + xgetptr $ + print (struct scrollbar *) $ptr output *$ echo \n end @@ -323,10 +373,11 @@ Print $ as a scrollbar pointer. end define xprintsym - set $sym = (struct Lisp_Symbol *) ((((int) $arg0) & $valmask) | gdb_data_seg_bits) - set $sym_name = ((struct Lisp_String *)(($sym->xname & $valmask) | gdb_data_seg_bits)) + xgetptr $arg0 + set $sym = (struct Lisp_Symbol *) $ptr + xgetptr $sym->xname + set $sym_name = (struct Lisp_String *) $ptr output ($sym_name->data[0])@($sym_name->size_byte < 0 ? $sym_name->size : $sym_name->size_byte) - echo \n end document xprintsym Print argument as a symbol. @@ -358,14 +409,16 @@ end define xbacktrace set $bt = backtrace_list while $bt - set $type = (enum Lisp_Type) ((*$bt->function >> gdb_valbits) & 0x7) + xgettype (*$bt->function) if $type == Lisp_Symbol - xprintsym *$bt->function + xprintsym (*$bt->function) + echo \n else printf "0x%x ", *$bt->function if $type == Lisp_Vectorlike - set $size = ((struct Lisp_Vector *) ((*$bt->function & $valmask) | gdb_data_seg_bits))->size - output (enum pvec_type) (($size & PVEC_FLAG) ? $size & PVEC_TYPE_MASK : 0) + xgetptr (*$bt->function) + set $size = ((struct Lisp_Vector *) $ptr)->size + output ($size & PVEC_FLAG) ? (enum pvec_type) ($size & PVEC_TYPE_MASK) : $size else printf "Lisp type %d", $type end @@ -381,16 +434,17 @@ document xbacktrace end define xreload - set $valmask = ((long)1 << gdb_valbits) - 1 - set $nonvalbits = gdb_emacs_intbits - gdb_valbits + set $tagmask = (((long)1 << gdb_gctypebits) - 1) + set $valmask = gdb_use_lsb ? ~($tagmask) : ((long)1 << gdb_valbits) - 1 end document xreload When starting Emacs a second time in the same gdb session under - FreeBSD 2.2.5, gdb 4.13, $valmask and $nonvalbits have lost + FreeBSD 2.2.5, gdb 4.13, $valmask have lost their values. (The same happens on current (2000) versions of GNU/Linux with gdb 5.0.) This function reloads them. end +xreload define hook-run xreload @@ -416,3 +470,5 @@ break abort # before Emacs exits. Perhaps we should put the break somewhere else # instead... break x_error_quitter + +# arch-tag: 12f34321-7bfa-4240-b77a-3cd3a1696dfe diff --git a/src/.gitignore b/src/.gitignore index f1a15019c6f..406ff7cd5e2 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,18 +1,19 @@ +*-spd *.core +*.pdb +.gdb_history Makefile Makefile.c TAGS-LISP +_gdbinit bootstrap-emacs config.h config.stamp emacs emacs-* epaths.h +gdb.ini obj prefix-args stamp-oldxmenu temacs -_gdbinit -gdb.ini -*-spd -*.pdb diff --git a/src/ChangeLog b/src/ChangeLog index 6c92bf7cd88..c9cf12dc159 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,2703 @@ +2004-04-14 Luc Teirlinck <teirllm@auburn.edu> + + * fileio.c (Fverify_visited_file_modtime, Fvisited_file_modtime): + Add hyperlink to Elisp manual to the docstring. + +2004-04-14 Stefan Monnier <monnier@iro.umontreal.ca> + + * callint.c (fix_command): Use XDCR. + +2004-04-14 Nick Roberts <nick@nick.uklinux.net> + + * window.c (Fget_lru_window): Doc fix. + +2004-04-14 Kim F. Storm <storm@cua.dk> + + * editfns.c (Fformat): Fix allocation size of precision array. + + * dispnew.c (update_window): Only set changed_p if + scrolling_window actually did scroll. + (scrolling_window): Only return 1 if we actually did scroll. + + * xdisp.c (get_glyph_string_clip_rect): Fix reduction of cursor + height to glyph height when cursor row is not fully visible. + (make_cursor_line_fully_visible): Add FORCE_P arg to return + failure in case row is higher than window. Callers changed. + (try_scrolling): Fix loop in scrolling if last_line_misfit (from Gerd). + Try to scroll partially visible, higher-than-window cursor row. + (redisplay_window): Always try to scroll partially visible, + higher-than-window cursor row - both initially and again with + centering_position = 0. + Clear desired matrix before retrying with centering_position = 0. + +2004-04-13 Joe Buehler <jbuehler@hekimian.com> + + * sheap.c, unexcw.c: New files. + +2004-04-12 Luc Teirlinck <teirllm@auburn.edu> + + * buffer.c (Fmake_indirect_buffer): Throw an error if the intended + base buffer has been killed. Correct the error message if the + base buffer does not exist. + +2004-04-12 Joe Buehler <jbuehler@hekimian.com> + + * s/cygwin.h: Changes for Cygwin unexec() support, changes in + Cygwin itself. Add support for Xaw3d scrollbars. + + * puresize.h: Set up PURE_P() for Cygwin unexec() support. + + * lastfile.c: Define my_endbss[] for Cygwin unexec() support. + + * gmalloc.c (__default_morecore): Use bss_sbrk(), not __sbrk(), + before Cygwin unexec. + + * Makefile.in: Link changes for Cygwin unexec() support. + +2004-04-12 Andreas Schwab <schwab@suse.de> + + * buffer.c (Fmake_indirect_buffer): Check that NAME is a string. + +2004-04-11 Luc Teirlinck <teirllm@auburn.edu> + + * buffer.c (Fgenerate_new_buffer_name): Return NAME argument if + IGNORE argument equals NAME. Doc fix. + +2004-04-11 Masatake YAMATO <jet@gyve.org> + + * buffer.c (fix_start_end_in_overlays): Make overlays + empty if they are backwards. + +2004-04-09 Stefan Monnier <monnier@iro.umontreal.ca> + + * xfaces.c (face_color_supported_p): Fix compilation without X11. + +2004-04-07 Stefan Monnier <monnier@iro.umontreal.ca> + + * doc.c (Fsnarf_documentation): Ignore new file name entries. + +2004-04-06 Kim F. Storm <storm@cua.dk> + + * msdos.c (clear_mouse_face): Only clear mouse highlight if not hidden. + (dos_rawgetc): Set mouse_face_hidden after clearing highlight. + + * w32term.c (w32_read_socket): Set mouse_face_hidden after + clearing highlight. + + * xdisp.c (clear_mouse_face): Only clear mouse highlight if not hidden. + + * xterm.c (handle_one_xevent): Set mouse_face_hidden after + clearing highlight. + + * indent.c (vmotion): Do not reserve one column for continuation + marks on window frames. + +2004-04-04 Eli Zaretskii <eliz@gnu.org> + + * charset.h (SINGLE_BYTE_CHAR_P): Fix macro to avoid warnings + from GCC. + +2004-04-03 Stefan Monnier <monnier@iro.umontreal.ca> + + * .gdbinit-union: Remove. + + * .gdbinit: Make it work for USE_LSB_TAG and !NO_LISP_UNION. + (xgetptr, xgetint, xgettype): New funs. Use them everywhere. + ($nonvalbits): Remove. + ($valmask): Set it by calling xreload to avoid redundancy. + + * emacs.c (gdb_use_union, gdb_use_lsb): New vars. + (gdb_emacs_intbits): Remove. + +2004-03-31 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * data.c (Fbyteorder): Make test work even if unsigned is not 4 bytes. + +2004-03-30 Kenichi Handa <handa@m17n.org> + + * editfns.c (Fformat): Fix initialization of the array info. + +2004-03-30 Kim F. Storm <storm@cua.dk> + + * xterm.c (x_mouse_click_focus_ignore_position): New var. + (syms_of_xterm): DEFVAR_BOOL it. + (ignore_next_mouse_click_timeout): New var. + (handle_one_xevent): Clear it on KeyPress, set it on EnterNotify. + Use it to filter mouse clicks following focus event. + +2004-03-29 David Ponce <david@dponce.com> + + * callint.c (Fcall_interactively): Fix last change. + +2004-03-28 Stefan Monnier <monnier@iro.umontreal.ca> + + * eval.c (Fcommandp): Simplify. + + * data.c (Finteractive_form): Rename from Fsubr_interactive_form. + Extend to handle all kinds of functions. + + * lisp.h (Finteractive_form): Declare. + + * callint.c (Fcall_interactively): Use it. + +2004-03-26 Kim F. Storm <storm@cua.dk> + + * xdisp.c (syms_of_xdisp): Include `void-variable' in list_of_error + to catch errors in calc_pixel_width_or_height during redisplay. + +2004-03-26 Masatake YAMATO <jet@gyve.org> + + * buffer.c (fix_start_end_in_overlays): Rename fix_overlays_in_range. + + * lisp.h (fix_start_end_in_overlays): Likewise. + + * insdel.c (adjust_markers_for_insert): Call fix_start_end_in_overlays. + + * editfns.c (Ftranspose_regions): Likewise. + +2004-03-20 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xterm.c (handle_one_xevent): Do not pass key press events to GTK. + +2004-03-19 Richard M. Stallman <rms@gnu.org> + + * s/sol2-6.h: Delete previous change. + +2004-03-19 Kim F. Storm <storm@cua.dk> + + * xdisp.c (move_it_in_display_line_to): Fix MOVE_TO_POS case when + to_charpos corresponds to newline in right fringe. Use local + BUFFER_POS_REACHED_P macro. + +2004-03-19 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xdisp.c (calc_pixel_width_or_height): Add ifdef HAVE_WINDOW_SYSTEM + to compile on non-window system. + +2004-03-19 Kim F. Storm <storm@cua.dk> + + * dispextern.h (calc_pixel_width_or_height): Add prototype. + + * image.c (Qcenter): Move to xdisp.c. + + * xdisp.c (Qcenter): Declare here. + (syms_of_xdisp): Intern and staticpro it. + (handle_single_display_prop): Allow space display property on all + platforms. + (display_mode_line): Set mode_line_p before displaying line. + (calc_pixel_width_or_height): Declare extern. Add separate :align-to + handling. Remove complex cases for fringes and scroll-bars. + Add left, right, and center alignment positions. Add text (area) + width/height. Return width or height for image specs. + (produce_stretch_glyph): Improve handling of :align-to. Is now + relative to left of text area by default, but other base offsets + can be specified -- also for text lines. + + * term.c (produce_glyphs): Handle IT_STRETCH. + (produce_stretch_glyph): New function to handle space width and + align-to display properties on non-window systems. + +2004-03-17 Stefan Monnier <monnier@iro.umontreal.ca> + + * fileio.c (Fread_file_name): Set completion-ignore-case for + case-insensitive systems. + +2004-03-14 Masatake YAMATO <jet@gyve.org> + + * xdisp.c (note_mode_line_or_margin_highlight): Accept HEADER_LINE + when keymap and cursor are setup. + +2004-03-14 Steven Tamm <steventamm@mac.com> + + * Makefile.in (XMENU_OBJ) [HAVE_CARBON]: Do not include xmenu.o. + +2004-03-14 Kim F. Storm <storm@cua.dk> + + * dispextern.h (x_find_image_file): Add prototype. + + * image.c (x_find_image_file): Make extern. + + * xfns.c (x_find_image_file): Remove prototype. + +2004-03-13 Eli Zaretskii <eliz@gnu.org> + + * Makefile.in (XMENU_OBJ): Include xmenu.o if HAVE_MENUS is defined. + + * emacs.c (main): Call syms_of_xmenu only if HAVE_MENUS is defined. + +2004-03-12 Richard M. Stallman <rms@gnu.org> + + * fns.c (internal_equal): New arg PROPS controls comparing + text properties. All callers changed. + (Fequal_including_properties): New function. + (syms_of_fns): defsubr it. + +2004-03-12 Kim F. Storm <storm@cua.dk> + + Fix image support on MAC. From YAMAMOTO Mitsuharu. + + * dispextern.h (XImagePtr, XImagePtr_or_DC): Add typedefs. + (image_background, image_background_transparent): Fix prototypes. + + * image.c (XImagePtr, XImagePtr_or_DC): Move typedefs to dispextern.h. + + * macfns.c (x_list_fonts, x_get_font_info, x_load_font) + (x_query_font, x_find_ccl_program, x_set_window_size) + (x_make_frame_visible, mac_initialize, XCreatePixmap) + (XCreatePixmapFromBitmapData, XFreePixmap, XSetForeground) + (mac_draw_line_to_pixmap): Move prototypes to macterm.h. + + * macterm.h (x_list_fonts, x_get_font_info, x_load_font) + (x_query_font, x_find_ccl_program, x_set_window_size) + (x_make_frame_visible, mac_initialize, XCreatePixmap) + (XCreatePixmapFromBitmapData, XFreePixmap, XSetForeground) + (mac_draw_line_to_pixmap): Add prototypes. + +2004-03-12 YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> + + * macterm.c (XTread_socket): Fix mouse click on tool bar. + +2004-03-11 Kim F. Storm <storm@cua.dk> + + * dispextern.h: Move image related prototypes from xfns.c section + to image.c. Condition them by HAVE_WINDOW_SYSTEM rather than + HAVE_X_WINDOWS. + + * Makefile.in (XOBJ): Consolidate into one list. Add image.o. + Move gtkutil.o to new GTK_OBJ list. + (XMENU_OBJ) [HAVE_MENUS]: Move declaration to proper place. + (GTK_OBJ) [USE_GTK]: New declaration. + (obj): Add $(GTK_OBJ) to list. + +2004-03-11 Steven Tamm <steventamm@mac.com> + + * image.c [MAC_OSX]: Include sys/stat.h + + * macfns.c (syms_of_macfns): Remove definitions of things now + defined in image.c + +2004-03-11 Kim F. Storm <storm@cua.dk> + + The following changes consolidates the identical/similar image + support code previously found in xfns.c, w32fns.c, and macfns.c + into a new file image.c. + + * makefile.w32-in (OBJ1): Add image.o. + ($(BLD)/image.$(O)): Add dependencies. + + * Makefile.in (XOBJ, MAC_OBJ): Add image.o. + (image.o): Add dependencies. + + * image.c: New file with consolidated image support code. + (COLOR_TABLE_SUPPORT): New define to control whether + color table support is available (X only). + (Bitmap_Record): Common name for x_bitmap_record, + w32_bitmap_record, and mac_bitmap_record. + (XImagePtr): Common name for pointer to XImage or equivalent. + (XImagePtr_or_DC): New type to simplify code sharing; equivalent + to XImagePtr on X+MAC, and to HDC on W32. + (GET_PIXEL): Wrapper for XGetPixel or equivalent. + (NO_PIXMAP): Common name for "None" or equivalent. + (PNG_BG_COLOR_SHIFT): Bits to shift PNG background colors. + (RGB_PIXEL_COLOR): Common type for an integer "pixel color" value. + (PIX_MASK_RETAIN, PIX_MASK_DRAW): Portability macros (from macfns.c). + (FRAME_X_VISUAL, x_defined_color, DefaultDepthOfScreen): + Define with suitable equivalents on W32 and MAC for code sharing. + (XDrawLine): Define on MAC for code sharing. + (Destroy_Image, Free_Pixmap): Wrappers for code sharing. + (IF_LIB_AVAILABLE): Macro to simplify code sharing. + (Vx_bitmap_file_path, Vimage_cache_eviction_delay) + (x_bitmap_height, x_bitmap_width, x_bitmap_pixmap) + (x_reference_bitmap, x_create_bitmap_from_data) + (x_create_bitmap_from_file, x_destroy_bitmap) + (x_destroy_all_bitmaps, x_create_bitmap_mask) + (XGetImage, XPutPixel, XGetPixel, XDestroyImage) + (QCascent, QCmargin, QCrelief, QCconversion, QCcolor_symbols) + (QCheuristic_mask, QCindex, QCmatrix, QCcolor_adjustment, QCmask) + (Qlaplace, Qemboss, Qedge_detection, Qheuristic, Qcenter) + (define_image_type, lookup_image_type, valid_image_p) + (image_error, enum image_value_type, struct image_keyword) + (parse_image_spec, image_spec_value, Fimage_size, Fimage_mask_p) + (make_image, free_image, prepare_image_for_display, image_ascent) + (four_corners_best, image_background, image_background_transparent) + (x_clear_image_1, x_clear_image, x_alloc_image_color) + (make_image_cache, free_image_cache, clear_image_cache) + (Fclear_image_cache, postprocess_image, lookup_image, cache_image) + (forall_images_in_image_cache, x_create_x_image_and_pixmap) + (x_destroy_x_image, x_put_x_image, x_find_image_file, slurp_file) + (find_image_fsspec, image_load_qt_1, image_load_quicktime) + (init_image_func_pointer, image_load_quartz2d) + (struct ct_color, init_color_table, free_color_table) + (lookup_rgb_color, lookup_pixel_color, colors_in_color_table) + (cross_disabled_images, x_to_xcolors, x_from_xcolors) + (x_detect_edges, x_emboss, x_laplace, x_edge_detection) + (x_disable_image, x_build_heuristic_mask) + (XBM support, XPM support, PBM support, PNG support, JPEG support) + (TIFF support, GIF support, Ghostscript support): Consolidate image + code from xfns.c, w32fns.c, and macfns.c. + (syms_of_image): Consolidate image related symbol setup here. + (init_image): Consolidate image related initializations here. + + * emacs.c (main) [HAVE_WINDOW_SYSTEM]: Add calls to syms_of_image + and init_image. Remove call to init_xfns. + + * macterm.h (struct mac_bitmap_record): Add file member. + Not currently used, but simplifies code sharing. + + * macfns.c (Vx_bitmap_file_path, Vimage_cache_eviction_delay) + (x_bitmap_height, x_bitmap_width, x_bitmap_pixmap) + (x_reference_bitmap, x_create_bitmap_from_data) + (x_create_bitmap_from_file, x_destroy_bitmap) + (x_destroy_all_bitmaps, x_create_bitmap_mask) + (XGetImage, XPutPixel, XGetPixel, XDestroyImage) + (QCascent, QCmargin, QCrelief, QCconversion, QCcolor_symbols) + (QCheuristic_mask, QCindex, QCmatrix, QCcolor_adjustment, QCmask) + (Qlaplace, Qemboss, Qedge_detection, Qheuristic, Qcenter) + (define_image_type, lookup_image_type, valid_image_p) + (image_error, enum image_value_type, struct image_keyword) + (parse_image_spec, image_spec_value, Fimage_size, Fimage_mask_p) + (make_image, free_image, prepare_image_for_display, image_ascent) + (four_corners_best, image_background, image_background_transparent) + (x_clear_image_1, x_clear_image, x_alloc_image_color) + (make_image_cache, free_image_cache, clear_image_cache) + (Fclear_image_cache, postprocess_image, lookup_image, cache_image) + (forall_images_in_image_cache, x_create_x_image_and_pixmap) + (x_destroy_x_image, x_put_x_image, x_find_image_file, slurp_file) + (find_image_fsspec, image_load_qt_1, image_load_quicktime) + (init_image_func_pointer, image_load_quartz2d) + (struct ct_color, init_color_table, free_color_table) + (lookup_rgb_color, lookup_pixel_color, colors_in_color_table) + (cross_disabled_images, x_to_xcolors, x_from_xcolors) + (x_detect_edges, x_emboss, x_laplace, x_edge_detection) + (x_disable_image, x_build_heuristic_mask) + (XBM support, XPM support, PBM support, PNG support, JPEG support) + (TIFF support, GIF support, Ghostscript support): Merge with image + code from xfns.c and macfns.c into image.c. + (syms_of_xfns): Move image related symbols to image.c. + (init_external_image_libraries, init_xfns): Remove; initialization + moved to init_image in image.c. + + * w32fns.c (Vx_bitmap_file_path, Vimage_cache_eviction_delay) + (x_bitmap_height, x_bitmap_width, x_bitmap_pixmap) + (x_reference_bitmap, x_create_bitmap_from_data) + (x_create_bitmap_from_file, x_destroy_bitmap) + (x_destroy_all_bitmaps, x_create_bitmap_mask) + (QCascent, QCmargin, QCrelief, QCconversion, QCcolor_symbols) + (QCheuristic_mask, QCindex, QCmatrix, QCcolor_adjustment, QCmask) + (Qlaplace, Qemboss, Qedge_detection, Qheuristic, Qcenter) + (define_image_type, lookup_image_type, valid_image_p) + (image_error, enum image_value_type, struct image_keyword) + (parse_image_spec, image_spec_value, Fimage_size, Fimage_mask_p) + (make_image, free_image, prepare_image_for_display, image_ascent) + (four_corners_best, image_background, image_background_transparent) + (x_clear_image_1, x_clear_image, x_alloc_image_color) + (make_image_cache, free_image_cache, clear_image_cache) + (Fclear_image_cache, postprocess_image, lookup_image, cache_image) + (forall_images_in_image_cache, x_create_x_image_and_pixmap) + (x_destroy_x_image, x_put_x_image, x_find_image_file, slurp_file) + (struct ct_color, init_color_table, free_color_table) + (lookup_rgb_color, lookup_pixel_color, colors_in_color_table) + (cross_disabled_images, x_to_xcolors, x_from_xcolors) + (x_detect_edges, x_emboss, x_laplace, x_edge_detection) + (x_disable_image, x_build_heuristic_mask) + (XBM support, XPM support, PBM support, PNG support, JPEG support) + (TIFF support, GIF support, Ghostscript support): Merge with image + code from xfns.c and macfns.c into image.c. + (syms_of_xfns): Move image related symbols to image.c. + (init_external_image_libraries, init_xfns): Remove; initialization + moved to init_image in image.c. + + * xfns.c (Vx_bitmap_file_path, Vimage_cache_eviction_delay) + (x_bitmap_height, x_bitmap_width, x_bitmap_pixmap) + (x_reference_bitmap, x_create_bitmap_from_data) + (x_create_bitmap_from_file, x_destroy_bitmap) + (x_destroy_all_bitmaps, x_create_bitmap_mask) + (QCascent, QCmargin, QCrelief, QCconversion, QCcolor_symbols) + (QCheuristic_mask, QCindex, QCmatrix, QCcolor_adjustment, QCmask) + (Qlaplace, Qemboss, Qedge_detection, Qheuristic, Qcenter) + (define_image_type, lookup_image_type, valid_image_p) + (image_error, enum image_value_type, struct image_keyword) + (parse_image_spec, image_spec_value, Fimage_size, Fimage_mask_p) + (make_image, free_image, prepare_image_for_display, image_ascent) + (four_corners_best, image_background, image_background_transparent) + (x_clear_image_1, x_clear_image, x_alloc_image_color) + (make_image_cache, free_image_cache, clear_image_cache) + (Fclear_image_cache, postprocess_image, lookup_image, cache_image) + (forall_images_in_image_cache, x_create_x_image_and_pixmap) + (x_destroy_x_image, x_put_x_image, x_find_image_file, slurp_file) + (struct ct_color, init_color_table, free_color_table) + (lookup_rgb_color, lookup_pixel_color, colors_in_color_table) + (cross_disabled_images, x_to_xcolors, x_from_xcolors) + (x_detect_edges, x_emboss, x_laplace, x_edge_detection) + (x_disable_image, x_build_heuristic_mask) + (XBM support, XPM support, PBM support, PNG support, JPEG support) + (TIFF support, GIF support, Ghostscript support): Merge with + w32fns.c and macfns.c image code into image.c. + (syms_of_xfns): Move image related symbols to image.c. + (init_xfns): Remove; initialization moved to init_image in image.c. + + * lisp.h (syms_of_image, init_image): Add protoypes. + (init_xfns): Remove prototype. + + * dispextern.h (x_bitmap_height, x_bitmap_width, x_bitmap_pixmap) + (x_reference_bitmap, x_create_bitmap_from_data) + (x_create_bitmap_from_file, x_destroy_bitmap) + (x_create_bitmap_mask): Move prototypes from dispextern.h. + (gamma_correct) [MAC_OS]: Add prototype. + + * xterm.h (x_bitmap_height, x_bitmap_width, x_bitmap_pixmap) + (x_reference_bitmap, x_create_bitmap_from_data) + (x_create_bitmap_from_file, x_destroy_bitmap) + (x_create_bitmap_mask): Move prototypes to dispextern.h. + +2004-03-09 Kenichi Handa <handa@etlken2> + + * coding.c (decode_coding_emacs_mule): Handle insufficent source + correctly. + +2004-03-04 Richard M. Stallman <rms@gnu.org> + + * s/sol2-6.h (LD_SWITCH_SYSTEM_TEMACS): New definition. + + * window.c (Fdisplay_buffer): Doc fix. + + * buffer.c (Fpop_to_buffer): Doc fix. + +2004-03-03 Kim F. Storm <storm@cua.dk> + + * xdisp.c (display_line): Fix call to get_overlay_arrow_glyph_row. + +2004-03-02 Stefan Monnier <monnier@iro.umontreal.ca> + + * editfns.c (Ftranslate_region): Lisp_Object/int mixup. + +2004-03-02 Richard M. Stallman <rms@gnu.org> + + * indent.c (compute_motion): Save vpos in prev_vpos, like hpos etc. + +2004-03-02 Kenichi Handa <handa@m17n.org> + + * doc.c (Fsubstitute_command_keys): Fix counding bytes. + +2004-03-02 Kim F. Storm <storm@cua.dk> + + * window.h (struct window): New member overlay_arrow_bitmap. + + * window.c (make_window): Initialize overlay_arrow_bitmap. + + * xdisp.c (Voverlay_arrow_variable_list): New variable to properly + implement and integrate multiple overlay arrows with redisplay. + (syms_of_xdisp): DEFVAR_LISP and initialize it. + (last_arrow_position, last_arrow_string): Replace by properties. + (Qlast_arrow_position, Qlast_arrow_string) + (Qoverlay_arrow_string, Qoverlay_arrow_bitmap): New variables. + (syms_of_xdisp): Intern and staticpro them. + (overlay_arrow_string_or_property, update_overlay_arrows) + (overlay_arrow_in_current_buffer_p, overlay_arrows_changed_p) + (overlay_arrow_at_row): New functions for multiple overlay arrows. + (redisplay_internal): Use them instead of directly accessing + Voverlay_arrow_position etc. for multiple overlay arrows. + (mark_window_display_accurate): Use update_overlay_arrows. + (try_cursor_movement): Use overlay_arrow_in_current_buffer_p. + (try_window_id): Use overlay_arrows_changed_p. + (get_overlay_arrow_glyph_row): Add overlay_arrow_string arg. + (display_line): Use overlay_arrow_at_row to check multiple + overlay arrows, and get relevant overlay-arrow-string and + overlay-arrow-bitmap. Set w->overlay_arrow_bitmap accordingly. + (produce_image_glyph): Set pixel_width = 0 for fringe bitmap. + (syms_of_xdisp): Remove last_arrow_position and last_arrow_string. + + * fringe.c (draw_fringe_bitmap): Use w->overlay_arrow_bitmap if set. + (update_window_fringes): Remove unused code. + +2004-03-01 Jason Rumney <jasonr@gnu.org> + + * w32term.c (w32_read_socket): Fix last change to ButtonPress handling. + +2004-03-01 Juanma Barranquero <lektu@terra.es> + + * fringe.c (Fdefine_fringe_bitmap): Fix typo in docstring. + + * makefile.w32-in ($(BLD)/fringe.$(O)): Add dependencies. + +2004-03-01 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xfns.c (Fx_display_color_cells): Use number of planes to calculate + how many colors can be displayed. + +2004-03-01 Kenichi Handa <handa@m17n.org> + + * editfns.c (Ftranslate_region): Handle multibyte chars in TABLE + correctly. + +2004-02-28 Kim F. Storm <storm@cua.dk> + + * dispnew.c (update_window): Update header line also if there are + no other changes in window (move code after set_cursor label). + + * lisp.h (mark_window_display_accurate): Remove prototype. + + * window.c (window_loop, Fforce_window_update): Force mode line + updates by setting prevent_redisplay_optimizations_p and + update_mode_lines. + +2004-02-28 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xfns.c (x_window): Fix indentation. + + * xterm.c (x_calc_absolute_position): Call x_real_positions + to get WM window sizes and use those to calculate position. + (x_set_offset): Remove code commented out. + +2004-02-28 Miles Bader <miles@gnu.org> + + * keyboard.c (adjust_point_for_property): #ifdef-out dodgy xassert. + +2004-02-28 Kim F. Storm <storm@cua.dk> + + * keyboard.c (kbd_buffer_store_event_hold): New function to store + an event into kbd fifo, but with special handling of quit event; + a quit event is saved for later, and further events are discarded + until the saved quit event has been processed. + (kbd_buffer_store_event): Use kbd_buffer_store_event_hold. + (gen_help_event): Store help event in kbd fifo. + (NREAD_INPUT_EVENTS): Remove. + (read_avail_input): Adapt to new read_socket_hook interface. + Remove allocation and initialization of local input_event buffer, + as read_socket_hook stores events directly in fifo. Allocate and + initialize local hold_quit event to handle postponed quit event + (and store it if set by kbd_buffer_store_event_hold). + + * keyboard.h (kbd_buffer_store_event_hold): Add prototype. + (gen_help_event): Fix prototype. + + * macterm.c (XTread_socket): Remove bufp_r and + numcharsp args. Add hold_quit arg. + Rework to use just one, local, inev input_event. Store inev + directly in fifo using kbd_buffer_store_event_hold. + + * sysdep.c (BUFFER_SIZE_FACTOR): Remove. + (read_input_waiting): Adapt to new read_socket_hook interface. + Remove allocation and initialization of local input_event buffer, + as read_socket_hook stores events directly in fifo. Allocate and + initialize local hold_quit event to handle postponed quit event + (and store it if set by kbd_buffer_store_event_hold). + + * term.c (read_socket_hook): Fix arg list. + + * termhooks.h (read_socket_hook): Fix prototype. + + * w32inevt.c (w32_console_read_socket): Remove bufp_r and + numcharsp args. Add hold_quit arg. + Rework to use just one, local, inev input_event. Store inev + directly in fifo using kbd_buffer_store_event_hold. + + * w32inevt.h (w32_console_mouse_position): Fix prototype. + + * w32term.c (w32_read_socket): Remove bufp_r and numcharsp args. + Add hold_quit arg. Rework to use just one, local, inev + input_event. Store inev directly in fifo using + kbd_buffer_store_event_hold. Update count in one place. + Postpone call to gen_help_event until inev is stored; use new + local do_help for this. + Remove local emacs_event in handing of ButtonPress event; just use + inev instead (so no reason to copy it later). + + * xsmfns.c (x_session_check_input): Remove numchars arg. + + * xterm.c (x_focus_changed, x_detect_focus_change): + Remove numchars arg. Always store event into bufp arg. + Return nothing. Callers changed accordingly. + (glyph_rect): Simplify. + (STORE_KEYSYM_FOR_DEBUG): New macro. + (SET_SAVED_MENU_EVENT): Use inev instead of bufp, etc. + (current_bufp, current_numcharsp) [USE_GTK]: Remove. + (current_hold_quit) [USE_GTK]: Add. + (event_handler_gdk): Adapt to new handle_one_xevent. + (handle_one_xevent): Remove bufp_r and numcharsp args. + Add hold_quit arg. Rework to use just one, local, inev + input_event. Store inev directly in fifo using + kbd_buffer_store_event_hold. Update count in one place. + Postpone call to gen_help_event until inev is stored; use new + local do_help for this. + Simplify handling of keysyms (consolidate common code). Fix bug + where count was updated with nchars instead of nbytes. + Remove local emacs_event in handing of ButtonPress event; just use + inev instead (so no reason to copy it later). + Remove `out' label. Rename label `ret' to `done'; add various + `goto done' to clarify code flow in deeply nested blocks. + (x_dispatch_event): Simplify as handle_one_xevent now calls + kbd_buffer_store_event itself. + (XTread_socket): Remove bufp_r and numcharsp args. Add hold_quit + arg. Call handle_one_xevent with new arglist. Store event from + x_session_check_input in fifo. + [USE_GTK]: Setup current_hold_quit. + Decrement handling_signal before unblocking input. + (x_initialize) [USE_GTK]: Initialize current_count. + + * xterm.h (x_session_check_input): Fix prototype. + +2004-02-26 YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> + + * s/darwin.h (LD_SWITCH_SYSTEM_TEMACS): Add `-framework QuickTime'. + + * dispextern.h [MAC_OSX]: Do not include Carbon/Carbon.h (now in + macgui.h). + + * emacs.c (main) [HAVE_CARBON]: Call init_xfns. + + * macgui.h [MAC_OSX]: Include Carbon/Carbon.h. + (mktime, DEBUG, Z, free, malloc, realloc, max, min) + (init_process) [MAC_OSX] : Avoid conflicts with Carbon/Carbon.h. + [!MAC_OSX]: Include QDOffscreen.h and Controls.h. + (INFINITY) [MAC_OSX]: Avoid conflict with definition in math.h. + (Bitmap): Remove typedef. + (Pixmap): Change int to GWorldPtr. + + * macmenu.c [MAC_OSX]: Don't include Carbon/Carbon.h (now in macgui.h). + + * macterm.h [MAC_OSX]: Don't include Carbon/Carbon.h (now in macgui.h). + (RED16_FROM_ULONG, GREEN16_FROM_ULONG, BLUE16_FROM_ULONG): + New #define to extract 16-bit depth color components from unsigned + long representation. + (PIX_MASK_DRAW, PIX_MASK_RETAIN): New #define to represent pixel + colors used for masks. + (struct mac_display_info): Add color_p. Remove n_cbits. + + * macfns.c: Include sys/types.h and sys/stat.h. + [MAC_OSX]: Do not include Carbon/Carbon.h (now in macgui.h). + Include QuickTime/QuickTime.h. + (XCreatePixmap, XCreatePixmapFromBitmapData, XFreePixmap) + (XSetForeground, mac_draw_line_to_pixmap): Add externs for + functions defined in macterm.c. + (XImagePtr): New typedef. Corresponds to XImage * in xfns.c. + (ZPixmap): New #define for compatibility with xfns.c. + (XGetImage, XPutPixel, XGetPixel, XDestroyImage) + (x_create_x_image_and_pixmap, x_destroy_x_image, x_put_x_image) + (find_image_fsspec, image_load_qt_1, image_load_quicktime): + New functions. + (four_corners_best, x_create_x_image_and_pixmap) + (x_destroy_x_image, unwind_create_frame, x_disable_image) + (x_edge_detection, init_color_table, colors_in_color_table) + (lookup_rgb_color, lookup_pixel_color, postprocess_image) + (x_put_x_image, slurp_file, xbm_scan, xbm_load, xbm_load_image) + (xbm_image_p, xbm_read_bitmap_data, xbm_file_p, x_to_xcolors) + (x_from_xcolors, x_detect_edges): New declarations (from xfns.c). + (mac_color_map_lookup, x_to_mac_color): Fix Lisp_Object/unsigned + long mixup. + (mac_defined_color, x_to_x_colors): Use RED16_FROM_ULONG etc. + (x_decode_color): Don't use n_cbits (in struct mac_display_info). + (x_set_foreground_color, x_set_cursor_color): Sync with w32fns.c. + (x_set_cursor_type, Fxw_color_values, valid_image_p) + (image_value_type, parse_image_spec, image_ascent, x_clear_image) + (x_alloc_image_color, clear_image_cache, lookup_image) + (x_find_image_file, xbm_read_bitmap_file_data) + (enum xbm_keyword_index, xbm_format, xbm_image_p, xbm_scan) + (xbm_read_bitmap_data, xbm_load, pbm_image_p, pbm_scan_number) + (enum pbm_keyword_index, pbm_format, enum png_keyword_index) + (png_format, png_image_p, enum jpeg_keyword_index, jpeg_format) + (jpeg_image_p, enum tiff_keyword_index, tiff_format, tiff_image_p) + (enum gif_keyword_index, gif_format, gif_image_p): Sync with xfns.c. + (x_make_gc): Sync with xfns.c. Enclose unused `border_tile' with + #if 0. + (x_free_gcs): Sync with xfns.c. Enclose unused `border_tile' with + #if 0. Free white_relief.gc and black_relief.gc. + (unwind_create_frame, x_emboss, x_laplace, x_edge_detection): + New functions (from xfns.c). + (Fx_create_frame): Record unwind_create_frame. + (Fxw_display_color_p): Use dpyinfo->color_p. + (Fx_display_grayscale_p, Fx_display_planes): Don't use + dpyinfo->n_cbits. + (Fx_display_color_cells): Use dpyinfo->n_planes; + (QCmatrix, QCcolor_adjustment, QCmask, Qemboss, Qedge_detection) + (Qheuristic, cross_disabled_images, emboss_matrix) + (laplace_matrix): New variables (from xfns.c). + (Fimage_size, Fimage_mask_p, four_corners_best, image_background) + (x_clear_image_1, postprocess_image, slurp_file, xbm_load_image) + (xbm_file_p, x_to_xcolors, x_from_xcolors, x_detect_edges) + (image_background_transparent): New function (from xfns.c). + Use PIX_MASK_DRAW/PIX_MASK_RETAIN. + (image_load_quicktime): Add declaration. + [MAC_OSX] (image_load_quartz2d): Likewise. + [MAC_OSX] (CGImageCreateWithPNGDataProviderProcType): New typedef. + [MAC_OSX] (MyCGImageCreateWithPNGDataProvider): New variable. + [MAC_OSX] (init_image_func_pointer, image_load_quartz2d): New funs. + (xbm_load_image_from_file, x_laplace_read_row) + (x_laplace_write_row, pbm_read_file): Remove functions. + [HAVE_XPM] (enum xpm_keyword_index, xpm_format, xpm_image_p) + (xpm_load): Sync with xfns.c (although XPM is not supported yet). + (colors_in_color_table): Sync with xfns.c (although not used). + (lookup_rgb_color): Don't lookup color table. Just do gamma + correction. + (COLOR_INTENSITY): New #define (from xfns.c). + (x_disable_image): New function (from xfns.c). + Use PIX_MASK_DRAW/PIX_MASK_RETAIN. + (x_build_heuristic_mask): Sync with xfns.c. + Use PIX_MASK_DRAW/PIX_MASK_RETAIN. + (HAVE_PBM): Remove #ifdef. + (pbm_load): Sync with xfns.c. Set img->width and img->height + before IMAGE_BACKGROUND. + (png_image_p, png_load): Don't enclose declarations with #if HAVE_PNG. + (Qpng, enum png_keyword_index, png_format, png_type, png_image_p): + Don't enclose with #if HAVE_PNG. + [!HAVE_PNG] (png_load) [MAC_OSX]: Use image_load_quartz2d if a + symbol _CGImageCreateWithPNGDataProvider is defined. + Otherwise use image_load_quicktime. + [!HAVE_PNG] (png_load) [!MAC_OSX]: Use image_load_quicktime. + [HAVE_PNG] (png_load): Sync with xfns.c. + Use PIX_MASK_DRAW/PIX_MASK_RETAIN. + (jpeg_image_p, jpeg_load): Don't enclose declarations with #if + HAVE_JPEG. + (Qjpeg, enum jpeg_keyword_index, jpeg_format, jpeg_type) + (jpeg_image_p): Don't enclose with #if HAVE_JPEG. + [!HAVE_JPEG] (jpeg_load) [MAC_OSX]: Use image_load_quartz2d. + [!HAVE_JPEG] (jpeg_load) [!MAC_OSX]: Use image_load_quicktime. + [HAVE_JPEG] (jpeg_load): Sync with xfns.c. + (tiff_image_p, tiff_load): Don't enclose declarations with #if + HAVE_TIFF. + (Qtiff, enum tiff_keyword_index, tiff_format, tiff_type) + (tiff_image_p): Don't enclose with #if HAVE_TIFF. + [!HAVE_TIFF] (tiff_load): Use image_load_quicktime. + [HAVE_TIFF] (tiff_error_handler, tiff_warning_handler): + New functions (from xfns.c). + [HAVE_TIFF] (tiff_load): Sync with xfns.c. + (gif_image_p, gif_load): Don't enclose declarations with #if HAVE_GIF. + (Qgif, enum gif_keyword_index, gif_format, gif_type, gif_image_p): + Don't enclose with #if HAVE_GIF. + [!HAVE_GIF] (gif_load): Use Quicktime Movie Toolbox if it is + animated gif. Otherwise use image_load_quicktime. + [HAVE_GIF] (gif_lib.h): Temporarily define DrawText as + gif_DrawText to avoid conflict with QuickdrawText.h. + [HAVE_GIF] (gif_load): Sync with xfns.c. + (enum gs_keyword_index, gs_format, gs_image_p, gs_load) + [HAVE_GHOSTSCRIPT] (x_kill_gs_process): Sync with xfns.c (although + Ghostscript is not supported yet). + (syms_of_macfns): Initialize Qemboss, Qedge_detection, Qheuristic, + QCmatrix, QCcolor_adjustment, and QCmask. Add DEFVAR_BOOL + cross_disabled_images (from xfns.c). Remove #if 0 for supported + image types. Remove #if HAVE_JPEG, HAVE_TIFF, HAVE_GIF, and + HAVE_PNG. Add defsubr for Simage_size and Simage_mask_p. + (init_xfns): Remove #if HAVE_JPEG, HAVE_TIFF, HAVE_GIF, and + HAVE_PNG. Call EnterMovies to support animated gifs. + Call init_image_func_pointer to bind a symbol + _CGImageCreateWithPNGDataProvider if it is defined. + + * macterm.c [MAC_OSX]: Don't include Carbon/Carbon.h (now in macgui.h). + (x_draw_bar_cursor): Sync declaration with xterm.c. + (XFreePixmap, mac_draw_rectangle_to_pixmap, mac_copy_area) + (mac_copy_area_to_pixmap): Implementation with GWorld (offscreen + graphics). + (mac_set_forecolor, mac_set_backcolor): Use RED16_FROM_ULONG etc. + (mac_draw_line_to_pixmap, XCreatePixmap) + (XCreatePixmapFromBitmapData, mac_fill_rectangle_to_pixmap) + (mac_copy_area_with_mask, mac_copy_area_with_mask_to_pixmap): + New functions. + (mac_draw_bitmap) [TARGET_API_MAC_CARBON]: + Use GetPortBitMapForCopyBits instead of the cast to Bitmap *. + Cast bits to char *. + (reflect_byte): New function (from w32fns.c). + (mac_create_bitmap_from_bitmap_data): Use it and don't stuff bits + due to byte alignment. + (mac_scroll_area) [TARGET_API_MAC_CARBON]: + Use GetPortBitMapForCopyBits instead of the cast to Bitmap *. + (XSetForeground): Remove static (now used in macfns.c). + (HIGHLIGHT_COLOR_DARK_BOOST_LIMIT): New #define (from w32term.c). + (mac_alloc_lighter_color, x_destroy_window): Sync with w32term.c. + (x_setup_relief_color, x_setup_relief_colors, x_draw_box_rect) + (x_draw_glyph_string_box, x_draw_image_foreground) + (x_draw_image_foreground_1, x_draw_image_glyph_string) + (x_draw_stretch_glyph_string, x_draw_glyph_string) + (x_draw_hollow_cursor, x_draw_bar_cursor, mac_draw_window_cursor): + Sync with xterm.c. + (x_draw_relief_rect): Sync with xterm.c. Make 1 pixel shorter + than the xterm.c version when a strictly horizontal or vertical + line is drawn. + (XTset_terminal_window): Add static. + (x_make_frame_visible): Add UNBLOCK_INPUT. + (x_free_frame_resources): New funcion (from xterm.c). + (XTread_socket): Call handle_tool_bar_click if mouse up/down event + occurs in tool bar area. + (mac_initialize_display_info): Remove dpyinfo->n_cbits. + Set dpyinfo->color_p. Determine dpyinfo->n_planes using HasDepth. + Initialize image cache. + (stricmp, wildstrieq, mac_font_pattern_match, mac_font_match): + Enclose unused functions with #if 0. + (Qbig5, Qcn_gb, Qsjis, Qeuc_kr): New variables. + (decode_mac_font_name): New function to apply code conversions + from a mac font name to an XLFD font name according to its script code. + (x_font_name_to_mac_font_name): Apply code conversion from an XLFD + font name to a mac font name according to REGISTRY and ENCODING fields. + (init_font_name_table) [TARGET_API_MAC_CARBON]: Don't use a font + whose name starts with `.'. + (init_font_name_table): Use decode_mac_font_name. Add both + jisx0208.1983-sjis and jisx0201.1976-0 entries if the script code + of a font is smJapanese. + (mac_do_list_fonts): New function to list fonts that match a given + pattern. + (x_list_fonts, XLoadQueryFont): Use it. + (XLoadQueryFont): Set rbearing field for each variable width + character to avoid needless redraw. + (syms_of_macterm): Initialize Qbig5, Qcn_gb, Qsjis, and Qeuc_kr. + +2004-02-26 Kim F. Storm <storm@cua.dk> + + * keyboard.c (NREAD_INPUT_EVENTS): Temporarily increase to 512 + as read_socket_hook handler on X aborts if buffer is too small + and W32 handler doesn't always check buffer limit. + + * xdisp.c (handle_single_display_prop): Handle left-fringe and + right-fringe similar to a display margin image. Specifically, + the characters having the fringe prop are no longer shown, and + we use IT_IMAGE/next_element_from_image with image_id = -1 to + do this. Set fringe bitmap face_id in it->face_id. + (produce_image_glyph): Handle image_id < 0 as "no image" case, but + still realize it->face (i.e. the fringe bitmap face). + +2004-02-25 Miles Bader <miles@gnu.org> + + * xdisp.c (check_it): Check string/string_pos consistency. + (init_iterator): Initialize string-related fields properly. + +2004-02-11 Miles Bader <miles@gnu.org> + + * xdisp.c (produce_image_glyph): Force negative descents to zero. + +2004-02-10 Miles Bader <miles@gnu.org> + + * xfns.c (lookup_image): Remove xassert(!interrupt_input_blocked); + BLOCK_INPUT can be nested, so it doesn't make much sense. + +2004-02-24 Michael Mauger <mmaug@yahoo.com> + + * w32fns.c (slurp_file, xbm_scan, xbm_load_image) + (xbm_read_bitmap_data): Use unsigned char for image data. + +2004-02-23 Luc Teirlinck <teirllm@auburn.edu> + + * abbrev.c (Finsert_abbrev_table_description): Doc fix. + +2004-02-22 Jason Rumney <jasonr@gnu.org> + + * w32term.c (w32_draw_fringe_bitmap): Draw overlaid bitmaps + correctly over other bitmaps. + +2004-02-21 Eli Zaretskii <eliz@gnu.org> + + * emacs.c (USAGE1): Split into two halves. + (USAGE2): Second half of the old USAGE1. + (USAGE3): Rename from USAGE2. + (USAGE4): Rename from USAGE3. + +2004-02-21 Juri Linkov <juri@jurta.org> + + * emacs.c (USAGE1): Add --no-desktop. Move --display from USAGE2. + Fix --multibyte. Move --help, --version to USAGE2. Add alias + --file. Fix -f, -l. Sort options. Untabify. + (USAGE2): Add -hb. Fix --name, --title. Sort options. Untabify. + +2004-02-19 Luc Teirlinck <teirllm@auburn.edu> + + * category.c (Fdefine_category, Fcategory_docstring) + (Fget_unused_category, Fset_category_table) + (Fcategory_set_mnemonics): Doc fixes. + +2004-02-20 Kim F. Storm <storm@cua.dk> + + * keyboard.c: Undo 2004-02-16 and 2004-02-17 changes. + The following changes are relative to the 2004-01-21 revision. + (NREAD_INPUT_EVENTS): Define as max number of input events to read + in one call to read_socket_hook. Value is 8. + (read_avail_input): Separate and rework handling of read_socket_hook + and non-read_socket_hook cases. Use smaller input_event buffer + in read_socket_hook case, and repeat if full buffer is read. + Use new local variable 'discard' to skip input after C-g. + In non-read_socket_hook case, just use a single input_event, and + call kbd_buffer_store_event on the fly for each character. + +2004-02-19 Stefan Monnier <monnier@iro.umontreal.ca> + + * lisp.h (union Lisp_Object): Give a more precise type for `type'. + Remove unused `gu' alternative. + +2004-02-19 Andreas Schwab <schwab@suse.de> + + * fringe.c (Fdefine_fringe_bitmap): Use && instead of & to avoid + warning. + +2004-02-18 Kim F. Storm <storm@cua.dk> + + * xdisp.c (get_window_cursor_type, display_and_set_cursor): + Fix last change. + +2004-02-17 Kim F. Storm <storm@cua.dk> + + * xdisp.c (fast_find_position): Fix return value of new version; + it was inverted compared to the 21.1 version. + (get_window_cursor_type): Don't look at glyph if NULL. + (display_and_set_cursor): Set glyph to NULL if cursor in fringe. + + * keyboard.c: Rework previous change; it didn't consider that the + buf array was allocated on the stack. + (prev_read): Remove variable. + (read_avail_input_buf): New static event buffer array. + (in_read_avail_input): New static variable to handle re-entrancy. + (read_avail_input): Change buf to pinter to read_avail_input_buf. + Use in_read_avail_input to handle re-entrance; when re-entered, + fully initialize and use tmp_buf array instead of read_avail_input_buf. + Do not initialize read_avail_input_buf in full here; instead assume it + is always cleared on entry. To ensure that, we clear (just) the + entries that were used before we return. + (init_keyboard): Initialize read_avail_input_buf here. + +2004-02-16 Jesper Harder <harder@ifa.au.dk> (tiny change) + + * cmds.c (Fend_of_line): Doc fix. + +2004-02-16 Dmitry Antipov <dmitry.antipov@mail.ru> (tiny change) + + * keyboard.c (prev_read): New static variable. + (read_avail_input): Use it to zero out only those slots in buf[] + that were used last time we were called. + +2004-02-16 Eli Zaretskii <eliz@gnu.org> + + * Makefile.in (obj): Move fringe.o from here... + (XOBJ, MAC_OBJ): ...to here. + +2004-02-16 Stephen Eglen <stephen@gnu.org> + + * fringe.c (init_fringe_bitmap): Define j in MAC_OS code. + +2004-02-15 Stefan Monnier <monnier@iro.umontreal.ca> + + * data.c (Fbyteorder): + * fringe.c (Fdefine_fringe_bitmap): + * xdisp.c (handle_single_display_prop): + * xselect.c (x_handle_dnd_message): Lisp_Object/int mixup. + +2004-02-16 Jason Rumney <jasonr@gnu.org> + + * w32term.c (w32_draw_fringe_bitmap): Handle overlay fringe bitmaps. + +2004-02-15 Steven Tamm <steventamm@mac.com> + + * macterm.c (Vmac_emulate_three_button_mouse): New variable for + controlling emulation of a three button mouse with option and + command keys. + (Qreverse, mac_get_enumlated_btn): Handle the emulation + (mac_event_to_emacs_modifiers, XTread_socket): Ditto. + +2004-02-15 Kim F. Storm <storm@cua.dk> + + * buffer.c (syms_of_buffer): Doc fix for indicate-buffer-boundaries. + + * fringe.c (init_fringe_bitmap) [MAC_OS, WORDS_BIG_ENDIAN]: + Perform byte-swapping. + +2004-02-14 Kim F. Storm <storm@cua.dk> + + * dispextern.h (struct draw_fringe_bitmap_params): Change member + bits from char to short to facilitate wider bitmaps. + (struct redisplay_interface): Fix prototype of define_fringe_bitmap + member. + + * fringe.c (struct fringe_bitmap): Change member bits from char to + short to facilitate 16 bits wide bitmaps. Modify all standard + bitmaps accordingly. + (BYTES_PER_BITMAP_ROW, STANDARD_BITMAP_HEIGHT): New macros. + (FRBITS): Use STANDARD_BITMAP_HEIGHT instead of just sizeof. + (draw_fringe_bitmap): Ditto. + (init_fringe_bitmap) [MAC_OS]: Don't bitswap. + (init_fringe_bitmap) [HAVE_X_WINDOWS]: Enhance bitswapping to + handle up to 16 bits wide bitmaps. + (Fdefine_fringe_bitmap): Doc fix. Handle wider bitmaps. + (Ffringe_bitmaps_at_pos): Add missing arg declarations. + + * macterm.c (mac_draw_bitmap): Handle 16 bits wide bitmaps directly. + (x_draw_fringe_bitmap): Use enhanced mac_draw_bitmap, so we no longer + need to call mac_create_bitmap_from_bitmap_data and mac_free_bitmap. + + * w32term.c (w32_define_fringe_bitmap): Bitmaps are now 16 bits wide, + so it is no longer necessary to expand them here. + + * xterm.c (x_draw_fringe_bitmap): Handle wider bitmaps (max 16 bits). + +2004-02-12 Kim F. Storm <storm@cua.dk> + + * window.c (Fwindow_fringes): Doc fix. + +2004-02-10 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xselect.c (x_get_foreign_selection): Add new optional parameter + time_stamp. + (Fx_get_selection_internal): Ditto, pass time_stamp to + x_get_foreign_selection. + + * data.c (Fbyteorder): New function. + +2004-02-09 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * atimer.c: Move include stdio.h to same place as in other files. + + * region-cache.c: Ditto. + + * sysdep.c: Ditto. + + * xfaces.c: Ditto. + +2004-02-09 Sam Steingold <sds@gnu.org> + + * w32term.c (w32_draw_fringe_bitmap): Fixed a typo in the last patch. + +2004-02-09 Kim F. Storm <storm@cua.dk> + + * fringe.c: New file. Move original fringe related declarations + and code from dispextern.h and xdisp.c here. + Rework code to support user defined fringe bitmaps, redefining + standard bitmaps, ability to overlay user defined bitmap with + overlay arrow bitmap, and add faces to bitmaps. + (Voverflow_newline_into_fringe): Declare here. + (enum fringe_bitmap_align): New enum. + (..._bits): All bitmaps are now defined without bitswapping; that + is now done in init_fringe_once (if necessary). + (standard_bitmaps): New array with specifications for the + standard fringe bitmaps. + (fringe_faces): New array. + (valid_fringe_bitmap_id_p): New function. + (draw_fringe_bitmap_1): Rename from draw_fringe_bitmap. + (draw_fringe_bitmap): New function which draws fringe bitmap, + possibly overlaying bitmap with cursor in right fringe or the + overlay arrow in the left fringe. + (update_window_fringes): Do not handle overlay arrow here. + Compare and copy fringe bitmap faces. + (init_fringe_bitmap): New function. + (Fdefine_fringe_bitmap, Fdestroy_fringe_bitmap): New DEFUNs to + define and destroy user defined fringe bitmaps. + (Fset_fringe_bitmap_face): New DEFUN to set face for a fringe bitmap. + (Ffringe_bitmaps_at_pos): New DEFUN to read current fringe bitmaps. + (syms_of_fringe): New function. Defsubr new DEFUNs. + DEFVAR_LISP Voverflow_newline_into_fringe. + (init_fringe_once, init_fringe): New functions. + (w32_init_fringe, w32_reset_fringes) [WINDOWS_NT]: New functions. + + * Makefile.in (obj): Add fringe.o. + (fringe.o): New dependencies. + + * dispextern.h (FRINGE_ID_BITS): New definition for number of + bits allocated to hold a fringe number. Increase number of bits + from 4 to 8 to allow user defined fringe bitmaps. + (struct glyph_row, struct it): New members left_user_fringe_bitmap, + left_user_fringe_face_id, right_user_fringe_bitmap, + right_user_fringe_face_id. + (enum fringe_bitmap_type, struct fringe_bitmap, fringe_bitmaps): + Move to new file fringe.c. + (MAX_FRINGE_BITMAPS): Define here. + (struct draw_fringe_bitmap_params): New members bits, cursor_p, + and overlay_p. Change member which to int. + (struct redisplay_interface): New members define_fringe_bitmap + and destroy_fringe_bitmap. + (valid_fringe_bitmap_id_p): Add prototype. + (w32_init_fringe, w32_reset_fringes) [WINDOWS_NT]: Add prototypes. + + * dispnew.c (row_equal_p): Compare fringe bitmap faces and overlay + arrows. + (update_frame): Do flush_display if force_flush_display_p to + ensure display (specifically fringes) are updated in a timely + manner when resizing the frame by dragging the mouse. + (update_window_line): Update row if overlay arrow changed. + (scrolling_window): Redraw fringe bitmaps if fringe bitmap faces + or overlay arrow changed. + + * emacs.c (main) [HAVE_WINDOW_SYSTEM]: Call init_fringe_once, + syms_of_fringe, and init_fringe. + + * frame.h (struct frame): New member force_flush_display_p. + + * lisp.h (syms_of_fringe, init_fringe, init_fringe_once): + Add prototypes. + + * macterm.c (mac_draw_bitmap): Add overlay_p arg. + (x_draw_fringe_bitmap): Handle overlayed fringe bitmaps; + thanks to YAMAMOTO Mitsuharu for advice on how to do this. + Use cursor color for displaying cursor in fringe. + (x_redisplay_interface): Add null handlers for + define_fringe_bitmap and destroy_fringe_bitmap functions. + + * w32term.c (w32_draw_fringe_bitmap): Copy unadapted code from + xterm.c to handle overlayed fringe bitmaps and to use cursor color + for displaying cursor in fringe. + (w32_define_fringe_bitmap, w32_destroy_fringe_bitmap): New W32 + specific functions to define and destroy fringe bitmaps in fringe_bmp. + (w32_redisplay_interface): Add them to redisplay_interface. + (w32_term_init): Call w32_init_fringe instead of explicitly + defining fringe bitmaps in fringe_bmp array. + (x_delete_display): Call w32_reset_fringes instead of explicitly + destroying fringe bitmaps in fringe_bmp array. + + * xdisp.c (Voverflow_newline_into_fringe, syms_of_xdisp) + (left_bits, right_bits, up_arrow_bits, down_arrow_bits) + (continued_bits, continuation_bits, ov_bits, first_line_bits) + (last_line_bits, filled_box_cursor_bits, hollow_box_cursor_bits) + (bar_cursor_bits, hbar_cursor_bits, zv_bits, hollow_square_bits) + (fringe_bitmaps, draw_fringe_bitmap, draw_row_fringe_bitmaps) + (draw_window_fringes, compute_fringe_widths, update_window_fringes): + Move fringe handling vars and code to new file fringe.c. + (handle_display_prop): Handle left-fringe and right-fringe + display properties; store user fringe bitmaps in iterator. + (move_it_in_display_line_to): Handle cursor in fringe at eob. + (clear_garbaged_frames): Set force_flush_display_p if resized. + (redisplay_window): Redraw fringe bitmaps if not just_this_one_p. + (display_line): Handle cursor in fringe at eob. + (display_line): Set row user fringe bitmaps from iterator. + + * xterm.c (x_draw_fringe_bitmap): Handle overlayed fringe bitmaps. + Use cursor color for displaying cursor in fringe. + (x_redisplay_interface): Add null handlers for + define_fringe_bitmap and destroy_fringe_bitmap functions. + +2004-02-07 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * macfns.c (Fx_change_window_property): Make doc string and + parameters same as for X version. + + * w32fns.c (Fx_change_window_property): Ditto. + +2004-02-07 Kim F. Storm <storm@cua.dk> + + * xdisp.c (hscroll_window_tree): Position cursor near to right + margin in hscrolled window when jumping to end of line (rather + than centering cursor). + + * process.c (wait_reading_process_input): Don't do adaptive read + buffering if waiting for a specific process. + +2004-02-05 Luc Teirlinck <teirllm@auburn.edu> + + * minibuf.c (Fminibufferp, Fread_from_minibuffer) + (Fread_minibuffer, Feval_minibuffer) + (Fread_string, Fread_no_blanks_input) + (Fcompleting_read): Doc fixes. + (syms_of_minibuf): Doc fixes for minibuffer-completion-table and + completion-regexp-list. Define Qcase_fold_search and staticpro it. + (read_minibuf): Fix initial comment. + (Ftry_completion, Fall_completions, Ftest_completion): Bind + case-fold-serach to the value of completion-ignore-case when + checking completion-regexp-list. + (Fdisplay_completion_list): Make it handle arguments that are + symbols. Doc fix. + +2004-02-05 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xterm.h: Add declaration of free_frame_menubar. + + * xfns.c (x_create_bitmap_mask): Removed unused variable depth. + (x_set_menu_bar_lines): Added ! defined USE_GTK for olines. + (Fx_change_window_property): Add declaration of parameters type and + format. Remove unused variable cons. + + * xselect.c: Include stdio,h. + +2004-02-05 Kenichi Handa <handa@m17n.org> + + * fns.c (Fset_char_table_range): Fix previous change. + + * buffer.c (Fset_buffer_multibyte): Fix docstring. + +2004-02-04 Luc Teirlinck <teirllm@auburn.edu> + + * editfns.c (Fchar_after, Fchar_before): Doc fixes. + +2004-02-04 Stefan Monnier <monnier@iro.umontreal.ca> + + * keymap.c (Vmouse_events): Rename from Vmenu_events. + (syms_of_keymap): Add mouse-[45], header-line, and mode-line to it. + +2004-02-04 Kenichi Handa <handa@m17n.org> + + * fns.c (Fset_char_table_range): Handle charsets ascii, + eight-bit-control, and eight-bit-graphic correctly. + +2004-02-03 Jason Rumney <jasonr@gnu.org> + + * w32select.c (Fw32_set_clipboard_data): Make coding iso2022 safe. + + * w32fns.c (x_to_w32_font): Likewise. + +2004-02-03 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xterm.h: Add x_handle_dnd_message, x_check_property_data, + x_fill_property_data, x_property_data_to_lisp and check_x_display_info. + + * xterm.c (handle_one_xevent): Call x_handle_dnd_message for + ClientMessages. + + * xselect.c: Include termhooks.h and X11/Xproto.h + (x_check_property_data, x_fill_property_data) + (x_property_data_to_lisp, mouse_position_for_drop) + (Fx_get_atom_name, x_handle_dnd_message): New functions for DND support. + (Fx_send_client_event): Move here from xfns.c. + (syms_of_xselect): Add Sx_get_atom_name and Sx_send_client_message. + + * xfns.c (x-send-client-message): Move to xselect.c + (Fx_change_window_property): Add optional arguments TYPE, FORMAT and + OUTER_P. + (Fx_window_property): Add optional arguments TYPE, SOURCE, DELETE_P, + VECTOR_RET_P. Handle AnyPropertyType. Call x_property_data_to_lisp + if vector_ret_p is true. + (syms_of_xfns): Sx_send_client_message moved to xselect.c. + +2004-02-02 Eli Zaretskii <eliz@gnu.org> + + * fileio.c (Fcopy_file): If NEWNAME is a directory, expand the + basename of FILE relative to it, not FILE itself. + +2004-02-02 Kenichi Handa <handa@m17n.org> + + * coding.c (coding_restore_composition): Check invalid + composition data more rigidly. + +2004-01-30 Luc Teirlinck <teirllm@auburn.edu> + + * fileio.c (Fread_file_name_internal): Correctly handle the case + where insert-default-directory is nil. + (Fread_file_name): Always return an empty string if the user exits + with an empty minibuffer. Adapt the docstring accordingly. + (syms_of_fileio): Adapt the docstring of insert-default-directory + to the change in Fread_file_name. + +2004-01-29 Eli Zaretskii <eliz@gnu.org> + + * alloca.c [!alloca]: Fix the prototype for xfree. + +2004-01-29 Kenichi Handa <handa@m17n.org> + + * fns.c (string_char_to_byte): Optimize for ASCII only string. + (string_byte_to_char): Likewise. + +2004-01-28 Peter Runestig <peter@runestig.com> + + * makefile.w32-in, w32fns.c: Add `default-printer-name' function. + +2004-01-27 Steven Tamm <steventamm@mac.com> + + * unexmacosx.c (unexec_copy): Do not copy more than was + requested to prevent overwriting during unexec. + +2004-01-27 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * process.c (sigchld_handler): Add comment about not calling malloc. + + * process.h: Add extern to synch_process_termsig. + +2004-01-27 Steven Tamm <steventamm@mac.com> + + * macterm.c (make_mac_frame, make_mac_terminal_frame): + Move setting of scroll bars from make_mac_frame to + make_mac_terminal_frame to prevent clobbering of scroll-bar-mode. + +2004-01-26 Richard M. Stallman <rms@gnu.org> + + * search.c (Freplace_match): Handle nonexistent + back-references properly. + +2004-01-03 Richard M. Stallman <rms@gnu.org> + + * window.c (decode_any_window): New function. + (Fwindow_height, Fwindow_width, Fwindow_edges) + (Fwindow_pixel_edges, Fwindow_inside_edges) + (Fwindow_inside_pixel_edges): Use decode_any_window. + +2004-01-27 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * process.h: synch_process_termsig new variable. + + * callproc.c: Define synch_process_termsig. + (Fcall_process): Initiate synch_process_termsig to zero and + check if non-zero and get signal name after subprocess has ended. + + * process.c (sigchld_handler): Set synch_process_termsig + if terminated by a signal. synch_process_death setting removed. + + * sysdep.c (mkdir, rmdir): Also check synch_process_termsig. + +2004-01-26 Andreas Schwab <schwab@suse.de> + + * print.c (print_preprocess): Declare size as EMACS_INT to not + lose bits. + (print_object): Likewise. + * alloc.c (Fpurecopy): Likewise. + +2004-01-25 Luc Teirlinck <teirllm@auburn.edu> + + * window.c (Fwindow_minibuffer_p): Doc fix. + +2004-01-24 Jonathan Yavner <jyavner@member.fsf.org> + + * editfns.c (Fformat): Make both passes accept the same set of flags. + +2004-01-23 Kenichi Handa <handa@m17n.org> + + * fns.c (Fmd5): If OBJECT is a buffer different from the current + one, set buffer to OBJECT temporarily. + +2004-01-21 Stefan Monnier <monnier@iro.umontreal.ca> + + * keyboard.c (kbd_buffer_gcpro): Remove. + (kbd_buffer_store_event, clear_event, Fdiscard_input) + (stuff_buffered_input, init_keyboard, syms_of_keyboard): + Don't initialize and/or maintain the variable any more. It was made + redundant by my commit of 2003-06-15. + + * lisp.h [USE_LSB_TAG && !DECL_ALIGN]: Signal an error. + +2004-01-21 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * lisp.h: Add undef DECL_ALIGN. + +2004-01-21 Stefan Monnier <monnier@iro.umontreal.ca> + + * process.c (wait_reading_process_input) [SYNC_INPUT]: + Check interrupt_input_pending explicitly. + + * lisp.h (QUIT) [SYNC_INPUT]: Check interrupt_input_pending as well. + + * keyboard.c (handle_async_input): New fun, + extracted from input_available_signal. + (input_available_signal, reinvoke_input_signal): Use it. + +2004-01-20 Stefan Monnier <monnier@iro.umontreal.ca> + + * buffer.c (buffer_defaults, buffer_local_symbols): Use DECL_ALIGN. + + * lisp.h [USE_LSB_TAG]: Add definitions for Lisp_Object value + manipulation macros for when tags are in the lower bits. + (struct Lisp_Free) [USE_LSB_TAG]: Add padding. + (DECL_ALIGN): New macro. + (DEFUN): Use it. + + * lisp.h [ENABLE_CHECKING]: Don't force union type. + + * s/darwin.h (__attribute__): Remove outdated workaround. + + * macterm.c (main) [USE_LSB_TAG]: Don't range check the ram. + + * alloc.c (lisp_malloc, lisp_align_malloc) [USE_LSB_TAG]: + Don't check range of malloc address. + (pure_alloc) [USE_LSB_TAG]: Enforce alignment. + + * process.c (wait_reading_process_input): Lisp_Object/int mixup. + + * dired.c (Ffile_attributes): Lisp_Object/int mixup. + +2004-01-19 Kenichi Handa <handa@m17n.org> + + * fontset.c (fontset_font_pattern): Fix previous change. + +2004-01-16 Miles Bader <miles@gnu.ai.mit.edu> + + * xdisp.c (Voverflow_newline_into_fringe) + (move_it_in_display_line_to, redisplay_internal) + (update_window_fringes, redisplay_window, display_line, window): + Add `#ifdef HAVE_WINDOW_SYSTEM' around fringe-drawing stuff, so + that it compiles without a window-system. + * dispnew.c (direct_output_for_insert, update_window): Likewise. + +2004-01-16 Kim F. Storm <storm@cua.dk> + + * buffer.h (struct buffer): New member indicate_buffer_boundaries. + + * buffer.c (init_buffer_once): Set buffer_defaults and + buffer_local_flags for indicate_buffer_boundaries. + (syms_of_buffer): Defvar_per_buffer it, and defvar_lisp_nopro + default- variable for it. + + * dispextern.h (struct glyph_row): New members left_fringe_bitmap, + right_fringe_bitmap, redraw_fringe_bitmaps_p for new fringe handling. + New members exact_window_width_line_p and cursor_in_fringe_p for + overflowing newlines into right fringe. + New members indicate_bob_p, indicate_top_line_p, indicate_eob_p, + and indicate_bottom_line_p for buffer boundaries and scrolling. + (enum fringe_bitmap_type): Add UP_ARROW_BITMAP, DOWN_ARROW_BITMAP, + FIRST_LINE_BITMAP, LAST_LINE_BITMAP, FILLED_BOX_CURSOR_BITMAP, + HOLLOW_BOX_CURSOR_BITMAP, BAR_CURSOR_BITMAP, HBAR_CURSOR_BITMAP, + and HOLLOW_SQUARE_BITMAP. + (draw_fringe_bitmap, draw_window_fringes, update_window_fringes): + Add prototypes. + + * dispnew.c (row_equal_p, update_window_line): Compare fringe bitmaps + instead of related indicator fields. + Compare exact_window_width_line_p and cursor_in_mouse_face_p indicators. + (direct_output_for_insert): Handle exact width lines like + contined lines. Call update_window_fringes. + (update_window): Call update_window_fringes. + (scrolling_window): Don't skip desired rows with changed bitmaps. + Check if fringe bitmaps changes when assigning scrolled rows. + + * xdisp.c (Voverflow_newline_into_fringe): New variable. + (IT_OVERFLOW_NEWLINE_INTO_FRINGE): New macro. + (move_it_in_display_line_to): Overflow newline into fringe for + rows that are exactly as wide as the window. + (up_arrow_bits, down_arrow_bits, first_line_bits, last_line_bits) + (filled_box_cursor_bits, hollow_box_cursor_bits, bar_cursor_bits) + (hbar_cursor_bits, hollow_square_bits): New fringe bitmaps. + (fringe_bitmaps): Add new bitmaps. + (draw_fringe_bitmap): Make extern. Remove WHICH arg. + Select proper bitmap for cursor in fringe when appropriate. + Handle alignment of bitmap to top or bottom of row. + (draw_row_fringe_bitmaps): Don't select bitmaps here; that is now + done by update_window_fringes. + (update_window_fringes, draw_window_fringes): New functions. + (redisplay_internal): Call update_window_fringes in case only + cursor row is updated. + (redisplay_window): Call update_window_fringes. + Explicitly call draw_window_fringes if redisplay was done using + the current matrix or the overlay arrow is in the window. + (try_window_reusing_current_matrix): Mark scrolled rows for + fringe update (to update buffer-boundaries / scrolling icons). + (find_last_unchanged_at_beg_row): Handle exact width lines line + continued lines. + (display_line): Overflow newline into fringe for rows that are + exactly as wide as the window. Don't append space for newline + in this case. + (notice_overwritten_cursor): Explicitly clear cursor bitmap + in fringe as if it had been overwritten. + (erase_phys_cursor): Erase cursor bitmap in fringe. + (syms_of_xdisp): Mark show-trailing-whitespace and + void-text-area-pointer as user options. + DEFVAR_LISP Voverflow_newline_into_fringe. Enable by default. + + * xterm.c (x_update_window_end): Call draw_window_fringes. + (x_after_update_window_line): Just set redraw_fringe_bitmaps_p + in row instead of actually drawing fringe bitmaps. + (x_draw_fringe_bitmap): Handle bottom aligned bitmaps. + (x_draw_window_cursor): Draw cursor in fringe. + + * w32term.c (x_update_window_end): Call draw_window_fringes. + (x_after_update_window_line): Just set redraw_fringe_bitmaps_p + in row instead of actually drawing fringe bitmaps. + (w32_draw_fringe_bitmap): Handle bottom aligned bitmaps. + (w32_draw_window_cursor): Draw cursor in fringe. + + * macterm.c (x_update_window_end): Call draw_window_fringes. + (x_after_update_window_line): Just set redraw_fringe_bitmaps_p + in row instead of actually drawing fringe bitmaps. + (x_draw_fringe_bitmap): Handle bottom aligned bitmaps. + (mac_draw_window_cursor): Draw cursor in fringe. + +2004-01-16 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xterm.c (handle_one_xevent): Don't handle characters that are part + of an old style (XLookupString) compose sequence. + +2004-01-15 Kenichi Handa <handa@m17n.org> + + * search.c (Freplace_match): Use make_multibyte_string or + make_unibyte_string according to the buffer multibyteness. + +2004-01-14 Stefan Monnier <monnier@iro.umontreal.ca> + + * alloc.c (struct interval_block, struct string_block) + (struct symbol_block, struct marker_block, live_string_p) + (live_cons_p, live_symbol_p, live_float_p, live_misc_p): + Better preserve alignment for objects in blocks. + (FLOAT_BLOCK_SIZE): Adjust for possible alignment padding. + + * lread.c (defvar_per_buffer): Remove dead declaration. + + * macterm.c (do_check_ram_size): Don't hardcode the lisp address + space size. + +2004-01-12 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xmenu.c (popup_get_selection): Check new parameter down_on_keypress + if a key press should pop down. Only pop down if a key is pressed + outside the menu/dialog. + (create_and_show_popup_menu): Pass 0 for down_on_keypress to + popup_get_selection. + (create_and_show_dialog): Pass 1 for down_on_keypress to + popup_get_selection. + +2004-01-11 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * alloc.c (allocate_vectorlike): Surround calls to mallopt with + BLOCK/UNBLOCK_INPUT. + +2004-01-08 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xmenu.c (Fx_popup_dialog): Add an Ok button if no buttons are + specified. + +2004-01-08 Kenichi Handa <handa@m17n.org> + + * editfns.c (Fformat): Fix '&' to '&&'. + +2004-01-08 Andreas Schwab <schwab@suse.de> + + * print.c (print_preprocess) <case Lisp_Vectorlike>: Only mask + size if PSEUDOVECTOR_FLAG is set. + +2004-01-07 Kenichi Handa <handa@m17n.org> + + * charset.c (Fdeclare_equiv_charset): Fix docstring. + + * fontset.c (fontset_ref_via_base): Fix previous change. + +2004-01-07 Kim F. Storm <storm@cua.dk> + + * process.c (read_process_output): Only activate adaptive + buffering if we read less than 256 bytes at a time. + +2004-01-06 Kim F. Storm <storm@cua.dk> + + * dispnew.c (buffer_posn_from_coords): Return both buffer/string + object and image object. Return glyph width and height. + (mode_line_string, marginal_area_string): Ditto. + + * dispextern.h (buffer_posn_from_coords, mode_line_string) + (marginal_area_string): Fix prototypes. + + * keyboard.h (POSN_POSN, POSN_SET_POSN): Rename macros from + POSN_BUFFER_POSN and POSN_SET_BUFFER_POSN. All uses changed. + (POSN_INBUFFER_P, POSN_BUFFER_POSN): New macros. + + * keyboard.c (make_lispy_position): Use modified mode_line_string, + buffer_posn_from_coords, and marginal_area_string functions to + include both string object and image object in the lispy position. + Also add actual glyph width and height to position. + (read_key_sequence): Use real buffer position from mouse + event to find keymap property even when click is in marginal area. + + * xdisp.c (note_mode_line_or_margin_highlight): Use modified + mode_line_string and marginal_area_string functions to handle + both string object and image object properties. + +2004-01-06 Andreas Schwab <schwab@suse.de> + + * syntax.c (skip_chars): Treat '-' at end of string as ordinary + character. + +2004-01-02 Andreas Schwab <schwab@suse.de> + + * macterm.c (emacs_options, x_initialized, same_x_server): + Remove unused (and duplicated) definitions. + +2004-01-02 Kim F. Storm <storm@cua.dk> + + * process.h (struct Lisp_Process): New members for adaptive read + buffering: adaptive_read_buffering, read_output_delay, and + read_output_skip. + + * process.c (ADAPTIVE_READ_BUFFERING): New conditional. + (READ_OUTPUT_DELAY_INCREMENT, READ_OUTPUT_DELAY_MAX) + (READ_OUTPUT_DELAY_MAX_MAX): New constants. + (process_output_delay_count, process_output_skip): New vars. + (Vprocess_adaptive_read_buffering): New variable. + (make_process): Initialize adaptive read buffering members. + (Fstart_process): Set adaptive_read_buffering member. + (deactivate_process): Cleanup adaptive read buffering. + (wait_reading_process_input): Temporarily omit delayed + subprocesses from the set of file descriptors to read from; + adjust the select timeout if we skipped any subprocesses. + (read_process_output): Increase adaptive read buffering delay if + we read less than a full buffer; reduce delay when we read a + full buffer. + (send_process): Simplify using local Lisp_Process var. + Reset adaptive read buffering delay after write. + (init_process): Initialize process_output_delay_count and + process_output_skip. + (syms_of_process): DEFVAR_LISP Vprocess_adaptive_read_buffering. + +2004-01-01 Jason Rumney <jasonr@gnu.org> + + * w32term.c (w32_text_out): Use s->font, for consistency with callers. + +2003-12-30 Luc Teirlinck <teirllm@auburn.edu> + + * print.c (Ferror_message_string): Add hyperlink in the docstring + to the definition of `signal' in the Elisp manual. + * eval.c (Fsignal): Ditto. + +2003-12-29 James Clark <jjc@jclark.com> (tiny change) + + * fns.c (internal_equal): Return t for two NaN arguments. + +2003-12-29 Richard M. Stallman <rms@gnu.org> + + * data.c (store_symval_forwarding): Handle setting + default-fill-column, etc., by changing the value in + buffers that use the default. + + * minibuf.c (Fset_minibuffer_window): Doc fix. + + * fileio.c (choose_write_coding_system): Ignore auto_saving + if using the visited file for auto saves. + (Fwrite_region): Don't update SAVE_MODIFF + if auto-saving in visited file. + +2003-12-29 Kenichi Handa <handa@m17n.org> + + * dispextern.h (face_font_available_p): Extern it. + + * fontset.c (Voverriding_fontspec_alist): New variable. + (lookup_overriding_fontspec): New function. + (fontset_ref_via_base): Call lookup_overriding_fontspec if necessary. + (fontset_font_pattern): Likewise. + (regulalize_fontname): New function. + (Fset_fontset_font): Call regulalize_fontname. + (Fset_overriding_fontspec_internal): New function. + (syms_of_fontset): Initialize and staticpro Voverriding_fontspec_alist. + Defsubr Sset_overriding_fontspec_internal. + + * xfaces.c (face_font_available_p): New function. + +2003-12-28 Richard M. Stallman <rms@gnu.org> + + * buffer.c (Fother_buffer): Don't crash if BUF is nil + or if its name is nil. + + * buffer.c (Fkill_buffer): Don't delete auto-save file + if it's the same as the visited file. + +2003-12-28 Luc Teirlinck <teirllm@auburn.edu> + + * coding.c (Fcheck_coding_system): Doc fix. + +2003-12-28 Kim F. Storm <storm@cua.dk> + + * Makefile.in (eval.o): Depend on dispextern.h. + + * dispnew.c (buffer_posn_from_coords): Fix calculation of dy for + image glyph using image's ascent. + (mode_line_string): Return image glyph as object clicked on. + Adjust y0 for image glyph using image's ascent. + + * dispextern.h (FACE_ID_BITS, MAX_FACE_ID): New defines. + (struct glyph): New members, ascent and descent. Used to save + this glyph's ascent and descent, instead of having. + (struct glyph): Declare member face_id using FACE_ID_BITS. + (find_hot_spot): Add prototype. + + * keyboard.c (Qimage): Remove extern (now in lisp.h). + (QCmap): Declare extern. + (make_lispy_position): When position is inside image hot-spot, + use hot-spot element's id as posn element. + + * lisp.h (IMAGEP): New macro to test for image object type. + (Qimage): Declare extern. + + * macfns.c (Qimage): Remove extern (now in lisp.h). + (valid_image_p, parse_image_spec): Use IMAGEP macro. + + * macterm.c (Qface, Qmouse_face): Remove unused externs. + + * w32fns.c (Qimage): Remove extern (now in lisp.h). + (valid_image_p, parse_image_spec): Use IMAGEP macro. + + * w32menu.c (Qmouse_click, Qevent_kind): Remove unused externs. + + * w32term.c (Qface, Qmouse_face): Remove unused externs. + + * xdisp.c (Qarrow, Qhand, Qtext, Qpointer): New variables for + pointer types. + (Qrelative_width, Qalign_to): Remove unused variables. + (Vvoid_text_area_pointer): Replace Vshow_text_cursor_in_void. + (QCmap, QCpointer, Qrect, Qcircle, Qpoly): New variables for + image maps. + (x_y_to_hpos_vpos): Return glyph relative coordinates through + new dx and dy args. + Remove buffer_only_p arg (always 0). Simplify code accordingly. + (get_glyph_string_clip_rect): Draw cursor using glyph's rather + than row's ascent and height, to get sensible height on tall rows. + (build_desired_tool_bar_string): Remove Qimage extern. + (get_tool_bar_item): Fix call to x_y_to_hpos_vpos. + (produce_image_glyph): Adjust it.ascent to minimum row ascent if + image glyph is alone on the last line. + (append_glyph, append_composite_glyph, produce_image_glyph) + (append_stretch_glyph): Set glyph's ascent and descent. + (on_hot_spot_p): New function to check if position is inside an + rectangular, circular, or polygon-shaped image hot-spot, + (find_hot_spot): New function to search for image hot-spot. + (Flookup_image_map): New defun to search for image hot-spot. + (define_frame_cursor1): New aux function to determine frame pointer. + (note_mode_line_or_margin_highlight, note_mouse_highlight): + Handle `pointer' text property and :pointer image property to + control frame pointer shape. Detect image hot-spots for pointer + and help_echo properties. Use define_frame_cursor1. + (note_mouse_highlight): Use Vvoid_text_area_pointer. + (syms_of_xdisp): Defsubr new defun. Intern and staticpro new variables. + DEFVAR_LISP Vvoid_text_area_pointer instead of Vshow_text_cursor_in_void. + + * xfaces.c (cache_face): Abort if c->size exceeds MAX_FACE_ID. + + * xfns.c (x_set_mouse_color): Remove bogus x_check_errors call. + (Qimage): Remove extern (now in lisp.h). + (valid_image_p, parse_image_spec): Use IMAGEP macro. + + * xmenu.c (show_help_event): Remove unused code. + + * xterm.c (Qface, Qmouse_face): Remove unused externs. + (x_draw_hollow_cursor): Draw cursor using glyph's rather than + row's ascent and descent, to get a sensible height on tall rows. + +2003-12-25 Luc Teirlinck <teirllm@auburn.edu> + + * minibuf.c (Fcompleting_read): Undo previous change. + +2003-12-25 Lars Hansen <larsh@math.ku.dk> + + * dired.c (Fdirectory_files, Fdirectory_files_and_attributes): + Arguments GCPRO'ed in call to file name handler. + +2003-12-25 Thien-Thi Nguyen <ttn@gnu.org> + + * termcap.c (tgetst1): Scan for "%pN"; if all + N are continuous in [1,9], remove all "%pN". + +2003-12-24 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * gtkutil.c (xg_frame_set_char_size): Call x_wm_set_size_hint. + + * xfaces.c (lface_fully_specified_p): Take into account that + MAC OS always have unspecified stipple. + +2003-12-24 Thien-Thi Nguyen <ttn@gnu.org> + + * tparam.c (tparam1): Add handling for `%pN', which + means use param N for the next substitution. + +2003-12-24 Thien-Thi Nguyen <ttn@gnu.org> + + * xfaces.c (Fcolor_gray_p): Fix omission bug: + In case `frame' is nil, consult the selected frame. + (Fcolor_supported_p): Likewise. + +2003-12-23 Luc Teirlinck <teirllm@auburn.edu> + + * fns.c (Frandom, Fstring_make_multibyte, Fset_char_table_range): + Doc fixes. + + * minibuf.c (read_minibuf): Allow INITIAL to be a cons of a string + and an integer. Adapt the introductory comment accordingly. + (Fread_from_minibuffer): Delete code moved into read_minibuf. + Doc fix. + (Fread_minibuffer, Fread_no_blanks_input): Adapt to changes in + read_minibuf. + (Fcompleting_read): Delete code moved into read_minibuf. + (Ftest_completion): Make it handle obarrays and hash tables correctly. + +2003-12-03 Kenichi Handa <handa@m17n.org> + + * coding.c (decode_coding_iso2022): Fix for preserving UTF-8 + encoding sequence. + +2003-12-01 Kenichi Handa <handa@m17n.org> + + * composite.c (syms_of_composite): Don't make the compostion hash + table week. + +2003-11-30 Luc Teirlinck <teirllm@auburn.edu> + + * intervals.h: Add EXFUN for Fget_char_property_and_overlay. + * textprop.c (Fget_char_property_and_overlay): New function. + (syms_of_textprop): Defsubr it. + +2003-11-29 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * dispnew.c (buffer_posn_from_coords): Add ifdef HAVE_WINDOW_SYSTEM + to compile on terminal configuration. + + * fileio.c (Fread_file_name): Check use_file_dialog also before + calling Fx_file_dialog. + + * fns.c: use_file_dialog: New variable. + (syms_of_fns): DEFVAR_BOOL use-file-dialog. + +2003-11-29 Kim F. Storm <storm@cua.dk> + + * msdos.c (Qcursor_type, Qbar, Qhbar): Declare extern. + (syms_of_msdos): Don't intern and staticpro them. + +2003-11-27 Kim F. Storm <storm@cua.dk> + + * dispnew.c (buffer_posn_from_coords): Calculate and return pixel + coordinates relative to glyph at posn. If glyph is an image, + return that as object at posn. Callers changed. + (mode_line_string, marginal_area_string): Calculate and return + pixel coordinates relative to glyph. Callers changed. + + * dispextern.h (buffer_posn_from_coords, mode_line_string) + (marginal_area_string): Fix prototypes. + (window_box_left_offset, window_box_right_offset): Add prototypes. + + * frame.h (get_specified_cursor_type, get_window_cursor_type): + Remove prototypes. + + * keyboard.h (EVENT_CLICK_COUNT, POSN_SCROLLBAR_PART): Fix defines. + + * keyboard.c (make_lispy_position): Add x and y coordinates + relative to the current glyph as 7th element of position. + If glyph is an image, return it in the object element. + (read_key_sequence): Skip checks for keymap property in cases + where POSN_STRING is not a string (e.g. an image). + + * xdisp.c (Vdisplay_pixels_per_inch): New variable. + (Vshow_text_cursor_in_void): New variable. + (glyph_to_pixel_coords): Don't use negative hpos. + (x_y_to_hpos_vpos): Fix for partially visible first glyph. + (append_stretch_glyph): Change ascent arg to be actual value + in pixels rather than ratio to height. Callers changed. + (calc_pixel_width_or_height): New aux function, implementing + pixel based artihmetic for glyph widths and heights. + (produce_stretch_glyph): Use calc_pixel_width_or_height for + :width, :height, :align-to, and :ascent, thus allowing these to + be specified in pixels as well as multiples of characters. + Don't produce stretch glyphs with zero width or height. + (get_specified_cursor_type): Declare static. + (get_window_cursor_type): Declare static. Add glyph arg to be + able to know when cursor is on an image; always substitute + hollow-box cursor for filled-box cursor on images, to avoid + negative images and flicker when blinking the cursor. + (display_and_set_cursor): Pass glyph to get_window_cursor_type. + (note_mode_line_or_margin_highlight): Use non-text cursor rather + than vertical scroll-bar cursor in display margins. + (note_mouse_highlight): Use non-text cursor rather than text + cursor in fringes and over images in the text area. + Use non-text cursor when mouse pointer is outside editable text, + i.e. in the void after end-of-line or end-of-buffer; this was + already done for W32, but is now standard for all systems -- + user can toggle show-text-cursor-in-void to get old behaviour. + (syms_of_xdisp): DEFVAR_LISP Vshow_text_cursor_in_void and + Vdisplay_pixels_per_inch. + +2003-11-25 Andreas Schwab <schwab@suse.de> + + * fns.c (internal_equal) <case Lisp_Vectorlike>: Declare size as + EMACS_INT to not lose bits. + (Ffillarray): Don't set bits beyond the size of a bool vector. + +2003-11-25 Kim F. Storm <storm@cua.dk> + + * print.c (Fredirect_debugging_output) [!GNU_LINUX]: Do not + define this defun on systems that cannot use stderr as lvalue. + +2003-11-24 Gerd Moellmann <gerd@gnu.org> + + * s/freebsd.h (LD_SWITCH_SYSTEM_TEMACS) + [__FreeBSD_version >= 500042]: Define as -znocombreloc because + ld's default is incompatible with unexec. + +2003-11-23 Kim F. Storm <storm@cua.dk> + + * window.c (enum window_loop): Add REDISPLAY_BUFFER_WINDOWS. + (window_loop): Handle REDISPLAY_BUFFER_WINDOWS. + (Fforce_window_update): New defun. + (syms_of_window): Defsubr it. + (Fset_window_margins, Fset_window_fringes): Doc fix. + + * print.c (Fredirect_debugging_output): New defun. + (syms_of_print): Defsubr it. + +2003-11-22 Luc Teirlinck <teirllm@auburn.edu> + + * fns.c (Fset_char_table_parent): Doc fix. + +2003-11-22 Kim F. Storm <storm@cua.dk> + + * dispnew.c (buffer_posn_from_coords): Return actual row/column + for glyph clicked on, rather than (unused) pixel positions. + (mode_line_string, marginal_area_string): Change X and Y args to + pointers for returning actual row/column for glyph clicked on. + Simplify and optimize loops. + + * dispextern.h (mode_line_string, marginal_area_string): + Update prototypes. + + * keyboard.c (make_lispy_position): New function for generating + mouse click positions from frame and pixel coordinates. + Enhanced to return buffer position and actual row/column for + events outside the text area using updated mode_line_string and + marginal_area_string functions. + Return left-fringe and right-fringe clicks as such, rather than + clicks in text area. + (make_lispy_event) [USE_X_TOOLKIT, USE_GTK]: Don't call + pixel_to_glyph_coords, as we never use the results. + (make_lispy_event): Use make_lispy_position for MOUSE_CLICK_EVENT, + WHEEL_EVENT, and DRAG_N_DROP_EVENT to replace redundant code. + Eliminate unused code in WHEEL_EVENT handling. + (make_lispy_movement): Use make_lispy_position. + + * window.c (coordinates_in_window): Remove redundant tests. + Fix returned X pixel value for left-margin. + + * xdisp.c (note_mode_line_or_margin_highlight): Adapt to new + mode_line_string and marginal_area_string parameters. + +2003-11-22 Lars Hansen <larsh@math.ku.dk> + + * w32.c (struct the_group, getgrgid): Add. + * mac.c (struct my_group, getgrgid): Add. + +2003-11-21 Luc Teirlinck <teirllm@auburn.edu> + + * fns.c (Fassq, Fassoc, Frassq, Frassoc): Doc fixes. + +2003-11-21 Lars Hansen <larsh@math.ku.dk> + + * dired.c (Ffile_attributes): Add parameter ID-FORMAT and + include in call to file name handler. Optionally translate numeric + UID and GID to strings. Update docstring. + (directory_files_internal): Add parameter ID-FORMAT. + (Fdirectory_files_and_attributes): Add parameter ID-FORMAT and + include in call to file name handler and call to + directory_files_internal. Update Docstring. + (Fdirectory_files): Add dummy parameter in call to + directory_files_internal. + * lisp.h (Qinteger): Add. + (Qinteger_or_floatp, Qinteger_or_float_or_marker_p): Remove. + (Ffile_attributes): Add parameter. + * data.c (Qinteger): Export. + +2003-11-21 Luc Teirlinck <teirllm@auburn.edu> + + * fns.c (Freverse, Fnreverse): Doc fixes. + +2003-11-19 Kim F. Storm <storm@cua.dk> + + * xdisp.c (init_iterator): Initialize it->start to position + before reseating (in case start position is invisible). + (init_to_row_start): Set it->start to row-start. + (redisplay_window): Accept optional_new_start if start position + is invisible (in which case IT_CHARPOS overshoots PT). + (display_line): Setup row->start from it->start (rather than + it->current which is wrong if first char on line is invisible). + When done, reseat it->start to it->current (= start of next row). + (expose_area): Fix exposure of text area when first char (e.g. TAB) + is only partially visible. + + * dispextern.h (struct it): New member start. + +2003-11-17 Stefan Monnier <monnier@iro.umontreal.ca> + + * alloc.c (make_float, Fcons): Clear the markbit at init time. + (make_float, Fcons, Fmake_symbol, allocate_misc): Move the increment + of block_index outside of the macro call. + (Fgarbage_collect): Remove null code. + + * m/amdx86-64.h: Don't redefine XPNTR. + + * keyboard.c (parse_modifiers, apply_modifiers): Use INTMASK instead + of VALMASK. + + * fns.c (hashfn_eq, hashfn_eql, hashfn_equal, hash_put) + (sxhash_string, sxhash): Use INTMASK instead of VALMASK. + (maybe_resize_hash_table): Use MOST_POSITIVE_FIXNUM. + + * lisp.h (VALMASK): Only define for non-union type. + (MARKBIT): Remove. + (ARRAY_MARK_FLAG): Use previous value of MARKBIT. + (XTYPE): Define unconditionally. + (XSETTYPE): Remove one more remnant. + (EQ): Define differently for the union and non-union cases. + (INTMASK): New bit mask. + (struct Lisp_Marker): Move down to prepare for upcoming patch. + (GC_EQ): Delegate to EQ. + + * coding.c (coding_restore_composition): Lisp_Object/int mixup. + +2003-11-17 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xterm.c (x_window_to_scroll_bar): Move check of display to + where window_id is compared. + +2003-11-17 Kim F. Storm <storm@cua.dk> + + * dispextern.h (struct it): New member first_vpos. + + * xdisp.c (start_display): Set it->first_vpos. + (try_window_id): Use first_vpos to start display in first _text_ + line if no reusable lines at start of window with header line. + +2003-11-16 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * w32fns.c (XPutPixel): + * w32bdf.c (w32_init_bdf_font): + * sunfns.c (sel_read): + * process.c (Fmake_network_process): + * frame.c (store_frame_param): + * fontset.c (Fset_fontset_font): + * emacs.c (shut_down_emacs): + * ccl.c (ccl_driver): Remove period at end of error message. + + * config.in: Regenerate. + + * xfns.c (x_window_to_frame, x_any_window_to_frame) + (x_non_menubar_window_to_frame, x_menubar_window_to_frame) + (x_top_window_to_frame): Add Display* argument to xg_win_to_widget. + (x_create_bitmap_mask, xg_set_icon, create_frame_xic) + (xic_set_statusarea, x_window, gif_load): Formatting adjustments. + + * xterm.h (struct x_display_info): New field xg_cursor for GTK. + + * xterm.c: Add Display * to x_window_to_scroll_bar declaration. + (XTmouse_position, handle_one_xevent): Pass Display* to + x_window_to_scroll_bar. + (x_window_to_scroll_bar): Take a Display* argument. + Check that display for frame is equal to Display* argument. + (event_handler_gdk): Remove current_dpyinfo. Get dpyinfo from + x_display_info_for_display instead. Use Display in xev instead + of GDK_DISPLAY. + (x_dispatch_event): Call x_display_info_for_display. + (XTread_socket): Move GTK part out of loop. current_dpyinfo removed. + (x_connection_closed): Call xg_display_close for GTK. + (x_term_init): Call xg_display_open for additional displays. + Initiate dpyinfo->xg_cursor with call to xg_create_default_cursor + for GTK. + + * xmenu.c (single_menu_item, mouse_position_for_popup) + (x_activate_menubar): Formatting adjustments. + + * xdisp.c (update_tool_bar, redisplay_tool_bar): Formatting + adjustments. + + * gtkutil.c (xg_get_gdk_display, xg_set_screen, xg_display_open) + (xg_display_close, xg_create_default_cursor) + (xg_get_gdk_pixmap_and_mask): New functions for multiple display + handling. + (xg_left_ptr_cursor): Remove. + (xg_set_cursor): Change cursor to GdkCursor*. Do not create + cursor here. + (xg_win_to_widget): Take Display* argument, call + gdk_xid_table_lookup_for_display. + (xg_create_frame_widgets, xg_get_file_name, create_menus) + (xg_create_widget, xg_modify_menubar_widgets): Call xg_set_screen. + (xg_create_widget, xg_create_scroll_bar): Use xg_cursor + in FRAME_X_DISPLAY_INFO. + (xg_get_scroll_id_for_window): Take Display* argument. + (update_frame_tool_bar): Call xg_get_gdk_pixmap_and_mask. + (xg_initialize): Remove xg_left_ptr_cursor. + + * gtkutil.h: xg_get_scroll_id_for_window, xg_win_to_widget takes + Display* argument also. Declare xg_display_open, + xg_display_close, xg_create_default_cursor. + +2003-11-14 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xterm.c (x_detect_focus_change): Do not change focus frame for + Enter/LeaveNotify if the current focus frame has explicit focus. + +2003-11-14 Kim F. Storm <storm@cua.dk> + + * dispnew.c (update_text_area): Fix redisplay error when hscroll + is active and first glyph is only partially visible. + +2003-11-13 Kenichi Handa <handa@m17n.org> + + * xdisp.c (select_frame_for_redisplay): New function. + (redisplay_internal): Record also selected_frame for + unwind_redisplay. Call select_frame_for_redisplay before + redrawing each frame. + (unwind_redisplay): Argument changed to a cons. + +2003-11-12 Luc Teirlinck <teirllm@auburn.edu> + + * fns.c (Fstring_to_multibyte): Doc fix. + +2003-11-11 Kenichi Handa <handa@m17n.org> + + * xterm.c (x_list_fonts): Fix excluding of auto-scaled fonts. + +2003-11-09 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xfns.c (x_window): Set XtNx and XtNy in shell widget for + program specified positions. + +2003-11-08 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xterm.c (XAW_ARROW_SCROLLBARS): Define it for Xaw 1.5E. + +2003-11-08 Kenichi Handa <handa@m17n.org> + + * Makefile.in (lisp): Add kannada.el. + (shortlisp): Likewise. + +2003-11-07 Kenichi Handa <handa@m17n.org> + + * coding.c (coding_allocate_composition_data): + Reset coding->composing to COMPOSITION_NO. + (coding_restore_composition): Detect invalid composition data. + Give Fstring and Fvector a Lispy integer, not C int. + +2003-11-05 Stefan Monnier <monnier@iro.umontreal.ca> + + * floatfns.c (Flogb): Don't use VALMASK. + + * m/amdx86-64.h (VALBITS, XINT, XUINT): Remove. + * m/ia64.h (VALBITS, XINT, XUINT): Remove. + + * lisp.h (XINT): Move the cast to clarify what is going on. + (GCTYPEMASK, XSETTYPE): Remove. + (XGCTYPE): Make it an alias of XTYPE. + +2003-11-03 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xterm.c (x_term_init): Fix formatting. + +2003-11-02 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * gtkutil.h: Declare xg_have_tear_offs, remove xg_keep_popup + and xg_did_tearoff. + + * gtkutil.c: Remove variable xg_did_tearoff. + (xg_have_tear_offs): New function. + (tearoff_remove): Just decrease xg_detached_menus. + (tearoff_activate): Increase xg_detached_menus and call + tearoff_remove when tearoff is removed. + (xg_keep_popup): Remove function. + (create_menus): Give add_tearoff_p as argument to recursive + call to create_menus. + (xg_create_widget): Use variables instead of multiple + strcmp. Tell create_menus to create tear off only for + menu bar menus. + (xg_update_menubar): Change title for a detached menu also. + (xg_modify_menubar_widgets): Always call xg_update_menubar, regardless + of deep_p. + (xg_initialize): Initialize xg_detached_menus, remove + initialization of xg_did_tearoff. + + * xmenu.c (set_frame_menubar): For GTK, set deep_p if + xg_have_tear_offs returns non-zero. + (create_and_show_popup_menu): Remove setting of xg_did_tearoff and + call to xg_keep_popup. + +2003-11-01 Andrew Choi <akochoi@shaw.ca> + + * macterm.c (XTread_socket): Handle menubar selection and grow + window only for mouseDown events. + +2003-10-31 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xterm.c (x_term_init): For GTK part, increase x_initialized + to check for more than one display. Use error instead of return 0. + +2003-10-31 Andrew Choi <akochoi@shaw.ca> + + * unexmacosx.c (unrelocate): New function (contributed by Nozomu Ando). + (copy_dysymtab): Call it. + +2003-10-31 Luc Teirlinck <teirllm@auburn.edu> + + * eval.c (Fdefvaralias): Doc fix. + +2003-10-26 Luc Teirlinck <teirllm@auburn.edu> + + * data.c (Fsetplist): Doc fix. + +2003-10-14 Lute Kamstra <lute@gnu.org> + + * window.c (Fset_window_fringes): Clarify docstring. + +2003-10-14 Kim F. Storm <storm@cua.dk> + + * window.c (Fset_window_margins): Simplify arg checking. + +2003-10-13 Richard M. Stallman <rms@gnu.org> + + * regex.c (MAX_BUF_SIZE): Reduce to 2**15. + (print_partial_compiled_pattern): Replace assert with a printout. + (skip_noops, mutually_exclusive_p): Change args, values to re_char *. + + * alloc.c (lisp_align_malloc): If BASE is 0, call memory_full. + + * window.c (Fset_window_margins): Allow only integers as args. + (syms_of_window) <special-display-buffer-names, special-display-regexps>: + Doc fixes. + +2003-10-13 Lute Kamstra <lute@gnu.org> + + * window.c (Fset_window_fringes): Elaborate docstring. + +2003-10-12 Andrew Choi <akochoi@shaw.ca> + + * macterm.c (XTread_socket): Call DragWindow only for mouseDown events. + + * s/darwin.h (GC_MARK_STACK): Define. + +2003-10-12 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * window.c (shrink_windows): New function. + (size_window): Call shrink_windows to calculate window sizes when + shrinking frame with more than one window. + +2003-10-12 Kim F. Storm <storm@cua.dk> + + * xdisp.c (compute_fringe_widths): Doc fix. + +2003-10-08 Kenichi Handa <handa@m17n.org> + + * coding.c (Fcoding_system_p): Return t for auto-loading coding system. + +2003-10-07 Kenichi Handa <handa@m17n.org> + + * coding.c (Qcoding_system_define_form): New variable. + (syms_of_coding): Intern and staticpro it. + (Fcheck_coding_system): Try to autoload the definition of + CODING-SYSTEM. + +2003-10-05 Luc Teirlinck <teirllm@auburn.edu> + + * fns.c (Frequire): Doc fix. + +2003-10-05 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xfns.c (Fx_send_client_event): New function as a base for + manipulating extended window manager hints. + (Fx_send_client_event): Remove unused variable s. + + * w32term.c (w32_read_socket): Remove call to x_check_fullscreen_move, + that function is removed. + + * xterm.c (x_set_offset): Use move_offset_left/top instead of + x/y_pixels_outer_diff. + (x_check_expected_move): Calculate move_offset_left/top. + + * xterm.h (struct x_output): New members: move_offset_top/left. + + * frame.c (x_set_frame_parameters): Remove x_fullscreen_move, + call x_set_offset directly. + + * frame.h (enum): FULLSCREEN_MOVE_WAIT removed. + + * frame.c (Fdelete_frame): Free decode_mode_spec_buffer. + + * xterm.c (x_delete_display): Free font names and font_encoder + in dpyinfo->font_table. + + * xfns.c (Fx_close_connection): Only call XFreeFont here. + Move xfree of font names to x_delete_display. + + * xterm.h (struct x_display_info): New member, wm_type. + (struct x_output): New members, expected_top/left and + check_expected_move. + + * xterm.c (handle_one_xevent): Reset wm_type when ReparentNotify + is received. + (handle_one_xevent): Rename x_check_expected_move from + x_check_fullscreen_move. + (x_set_offset): Only add WM decoration sizes to modified_top/left + for X_WMTYPE_A. Set check_expected_move when WM type is unknown. + (x_check_expected_move): Rename from x_check_fullscreen_move. + Removed fullscreen specific code. Use check_expected_move, + expected_left/top instead. Also, set wm_type. + (x_term_init): Initialize wm_type to unknown. + + * frame.c (x_fullscreen_move): Remove addition of WM decoration + sizes to move_x/y. + +2003-10-03 Kenichi Handa <handa@m17n.org> + + * macterm.c (x_load_font): Clear all members of FONTP before start + filling them. + +2003-10-02 Kenichi Handa <handa@m17n.org> + + * fontset.c (fs_load_font): Don't set fontp->font_encoder to NULL + before calling find_ccl_program_func. Call find_ccl_program_func + only when fontp->font_encoder is not NULL. + + * xterm.c (x_load_font): Clear all members of FONTP before start + filling them. + +2003-10-03 John Paul Wallington <jpw@gnu.org> + + * keymap.c (map_keymap): Don't abort when binding is a vector. + +2003-10-02 Jason Rumney <jasonr@gnu.org> + + * makefile.w32-in (emacs.o, coding.o, bytecode.o): + Sync dependencies with Makefile.in. + (alloca.o): Remove. + + * w32fns.c (w32_load_system_font): Clear all members of FONTP before + filling them. + + * w32bdf.c (w32_load_bdf_font): Likewise. + +2003-09-30 Richard M. Stallman <rms@gnu.org> + + * term.c (set_tty_color_mode): Calculate current_mode_spec + regardless of value of VAL. + + * intervals.c (graft_intervals_into_buffer): + Set BUF_INTERVALS (buffer)->up_obj when appropriate. + Handle over_used when splitting UNDER. + +2003-09-30 YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> + + * regex.c (regex_compile): Free the stack when returning from function. + +2003-09-28 Kenichi Handa <handa@m17n.org> + + * fontset.c (Finternal_char_font): Change return value to + cons (FONT-NAME . GLYPH-CODE). + +2003-09-28 Eli Zaretskii <eliz@gnu.org> + + * term.c (tty_setup_colors): Treat any negative argument as -1. + +2003-09-27 Gaute B Strokkenes <biggaute@uwc.net> (tiny change) + + * process.c (send_process): Delete unused temp_buf. + +2003-09-26 Dave Love <fx@gnu.org> + + * xterm.c (x_bitmap_mask): Declare. + +2003-09-25 Dave Love <fx@gnu.org> + + * Makefile.in (fns.o): Depend on md5.h. + +2003-09-25 Kim F. Storm <storm@cua.dk> + + * window.c (set_window_buffer): Fix redisplay problems when + switching between buffers with different display margin widths. + +2003-09-23 Kim F. Storm <storm@cua.dk> + + * process.c (set_socket_option): Fix :bindtodevice option. + (Fset_network_process_option): Update process contact list when + setting option succeeds. + (Fmake_network_process): Doc fix. + +2003-09-23 Dave Love <fx@gnu.org> + + * process.c (Fnetwork_interface_info): Use HAVE_STRUCT_IFREQ... macros. + +2003-09-22 Eli Zaretskii <eliz@gnu.org> + + * term.c (set_tty_color_mode): Use INTEGERP to test whether a + color mode is an integer number (it could be -1). + +2003-09-22 Richard M. Stallman <rms@gnu.org> + + * intervals.c (graft_intervals_into_buffer): Correct the main loop + in the case where OVER is longer than UNDER. + +2003-09-22 Masatake YAMATO <jet@gyve.org> + + * window.c (Fset_window_scroll_bars): Validate the value of + `vertical_type'. + +2003-09-21 Kim F. Storm <storm@cua.dk> + + * frame.c (Vdefault_frame_scroll_bars): New variable. + (x_set_vertical_scroll_bars): Use it instead of hardcoded values. + (syms_of_frame): DEFVAR_LISP it, and initialize according to + window-system default scroll bar position. + + * window.c (Fwindow_scroll_bars): Doc fix. + +2003-09-19 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xterm.c (x_set_offset): Take window manager decorations into account. + +2003-09-19 Richard M. Stallman <rms@gnu.org> + + * atimer.h: Don't include lisp.h. + (P_): Define it here (as well as elsewhere). + + * print.c (Fprin1_to_string): Move the PRINTPREPARE + later, so that PRINTFINISH won't unbind Qinhibit_modification_hooks. + + * data.c (Fvariable_binding_locus): New function. + (syms_of_data): defsubr it. + (Flocal_variable_p): Delete duplicate call to indirect_variable. + +2003-09-18 Dave Love <fx@gnu.org> + + * alloc.c (GC_MALLOC_CHECK): Move conditional undef after lisp.h. + + * process.c (Fnetwork_interface_info): Fix type error. + (Fnetwork_interface_list): Doc fix. + (read_process_output, read_process_output): Delete unused var. + +2003-09-17 Kim F. Storm <storm@cua.dk> + + * process.c (Fnetwork_interface_list, Fnetwork_interface_info): + Require HAVE_NET_IF_H and HAVE_SYS_IOCTL_H to include these fns. + (Fnetwork_interface_info): Check that ifreq struct has required + fields before accessing them; this requires that those fields are + defined as macros, which may be too restrictive on some platforms, + but it is better than failing on other platforms. + (syms_of_process): Only defsubr above fns when included. + +2003-09-17 Dave Love <fx@gnu.org> + + * unexalpha.c: Don't include varargs.h. + +2003-09-17 Kim F. Storm <storm@cua.dk> + + * process.c (Fset_process_sentinel): Add sentinel to childp plist + for network process. + (socket_options): Add `:' prefix to option names. Add optbit field. + (set_socket_option): Remove no_error arg and special handling of s < 0. + Return 1<<optbit for known option, 0 for unknown. + Do not interpret 0 as false for boolean option (only nil). + Pass failed option and value to report_file_error. + (Fset_network_process_options): Replace by Fset_network_process_option. + (Fset_network_process_option): New function to set just one option. + (Fmake_network_process): Allow :coding arg to be a cons. + Allow :server arg to be an integer specifying backlog size. + Remove :options arg, and allow options to be specified directly + as :KEY, VALUE pairs. Parse these options before binding socket. + As before, :reuseaddr t is default for a server process, but this + can now be disabled by specifying :reuseaddr nil. + (Fnetwork_interface_info): Rename from Fget_network_interface_info. + (init_process): Availability of network options is now checked with + simpler syntax (featurep 'make-network-process :OPTION); use loop to + setup features. + (syms_of_process): Fix defsubr's for the replaced functions. + +2003-09-16 Dave Love <fx@gnu.org> + + * Makefile.in: Depend on coding.h. + +2003-09-14 Kim F. Storm <storm@cua.dk> + + * process.c [HAVE_SOCKETS]: Include sys/ioctl.h and net/if.h. + (Fnetwork_interface_list, Fget_network_interface_info): New defuns. + (syms_of_process): Defsubr them. + + * config.in: Regenerate. + +2003-09-12 Stefan Monnier <monnier@iro.umontreal.ca> + + * m/sr2k.h (XMARKBIT, XUNMARK): Remove. + * m/news-r6.h (XUNMARK): Remove. + * m/mips.h (XUNMARK): Remove. + * m/mips-siemens.h (XUNMARK): Remove. + * m/iris4d.h (XUNMARK): Remove. + * m/hp800.h (XMARKBIT, XUNMARK): Remove. + +2003-09-11 Stefan Monnier <monnier@iro.umontreal.ca> + + * lisp.h (VALBITS): Don't remove 1 for the markbit. + (union Lisp_Object): Use unsigned int for types. Remove markbit. + (MARKBIT): Remove 1 from VALBITS so we still use same old val. + (XTYPE): Use unsigned right-shift. + (XMARKBIT, XMARK, XUNMARK): Remove. + + * alloc.c (init_intervals, init_symbol, init_marker): + Don't preallocate anything. + (Fgarbage_collect, mark_object): Ignore the markbit. + + * bytecode.c (mark_byte_stack, unmark_byte_stack): Ignore the markbit. + +2003-09-08 Lute Kamstra <lute@gnu.org> + + * xdisp.c (pint2hrstr): New function. + (decode_mode_spec): Add `%i' and `%I' specs. + * buffer.c (syms_of_buffer): Document `%i' and `%I' constructs + for `mode-line-format'. + +2003-09-07 Andreas Schwab <schwab@suse.de> + + * alloc.c: Use long instead of int when casting ABLOCKS_BUSY to + avoid warning. + +2003-09-07 Eli Zaretskii <eliz@gnu.org> + + * editfns.c (region_limit): Support any non-zero value of BEGINNINGP. + +2003-09-03 Kim F. Storm <storm@cua.dk> + + * xdisp.c (get_window_cursor_type): Partially undo 2002-03-01 + change (superseded by 2002-08-30 change); the default blink-off + cursor is now again "no cursor". + +2003-09-01 Jason Rumney <jasonr@gnu.org> + + * makefile.w32-in (alloca.o): Remove. + (coding.o): Depend on intervals.h + (emacs.o, bytecode.o): Depend on window.h + +2003-09-01 Dave Love <fx@gnu.org> + + * Makefile.in (alloca.o): Remove commands. + (coding.o): Depend on intervals.h composite.h window.h. + (emacs.o): Depend on window.h keyboard.h keymap.h. + (gtkutil.o): Depend on keyboard.h charset.h coding.h. + (bytecode.o): Depend on window.h. + +2003-08-31 Jason Rumney <jasonr@gnu.org> + + * w32term.c (w32_per_char_metric): Allow cached metrics to be + returned even when font_type is unknown. + + * xdisp.c (init_iterator): Remove old WINDOWSNT conditional. + +2003-08-30 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xterm.c (x_term_init): Initialize new fields in x_display_info. + + * xterm.h (struct x_display_info): Add red/green/blue_bits and + *_offset. + + * xfns.c (lookup_rgb_color): Use new fields in x_display_info to + calculate pixel value. + +2003-08-29 Gerd Moellmann <gerd.moellmann@t-online.de> + + * xdisp.c (redisplay_internal): Fix change of 2003-04-30. + Don't tell redisplay display is accurate when it's actually been + paused for pending input. + +2003-08-29 Richard M. Stallman <rms@gnu.org> + + * dispnew.c (adjust_glyph_matrix): Call window_box + whenever W is nonzero. + + * data.c (Fmake_variable_buffer_local, Fmake_local_variable) + (Fkill_local_variable, Fmake_variable_frame_local) + (Flocal_variable_p, Flocal_variable_if_set_p): + Use indirect_variable to trace thru variable aliases. + + * config.in: Updated. + + * callint.c (Fcall_interactively): Save and restore + Vthis_command, Vthis_original_command, real_this_command, + and current_kboard->Vlast_command. + + * abbrev.c (Fexpand_abbrev): Insert before deleting. + +2003-08-29 Gerd Moellmann <gerd@gnu.org> + + * xfns.c (lookup_rgb_color): Handle TrueColor visuals specially. + +2003-08-28 David Abrahams <dave@boost-consulting.com> (tiny change) + + * coding.c (decode_coding_iso2022): Initialize local variable c2. + (decode_coding_sjis_big5): Likewise. + +2003-08-27 Jason Rumney <jasonr@gnu.org> + + * w32.c (sys_pipe): Protect against file descriptor overflow. + + * w32fns.c (syms_of_w32fns): Remove non-existent functions. + + * w32term.c (w32_read_socket): Fix WM_MOUSEWHEEL assignment. + +2003-08-26 Terje Rosten <terjeros@phys.ntnu.no> + + * xfns.c (Vgtk_version_string): New variable. + (syms_of_xfns): DEFVAR_LISP it. Provide gtk. + +2003-08-24 Eli Zaretskii <eliz@gnu.org> + + * term.c (term_init): Remove `const' from buffer_size's declaration. + + * Makefile.in (msdos.o): Depend on intervals.h. + + * msdos.c: Include intervals.h, since STRING_INTERVALS requires that. + +2003-08-21 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> + + * xterm.h (struct x_display_info): New fields: client_leader_window + and Xatom_wm_client_leader. + + * xterm.c (x_initialize): Move call to x_session_initialize to ... + (x_term_init): ... here. Initialize client_leader fields in dpyinfo. + + * xsmfns.c (create_client_leader_window): New function. + (x_session_initialize): Call create_client_leader_window, take + dpyinfo as argument. + + * xfns.c (Fx_create_frame): Set property WM_CLIENT_LEADER. + + * Makefile.in (xsmfns.o): Add more depenedencies. + +2003-08-21 Dave Love <fx@gnu.org> + + * m/iris4d.h: Use _MIPS_SZLONG, not _LP64. + +2003-08-21 Kenichi Handa <handa@m17n.org> + + * term.c (term_init): Fix previous change; don't rely on the + length of `buffer' if TERMINFO is defined. + +2003-08-20 Dave Love <fx@gnu.org> + + * atimer.h: Include lisp.h. + + * lisp.h (EMACS_LISP_H): New. + (popup_activated_flag): Don't declare. + + * alloca.c: Some merging with gnulib. Change logic and doc + concerning (x)malloc/(x)free -- no longer Emacs-specific. + [DO_BLOCK_INPUT]: Don't include lisp.h. + (xmalloc, xfree): Declare. + (malloc): Don't declare. + + * Makefile.in (LWLIB_OPTIONS): Remove (unused). + (alloca.o): Remove obsolete stuff concerning alloca.s. Depend on + atimer.h, blockinput.h. + + * alloc.c (lisp_align_malloc): Change type of `aligned'. + + * alloca.s: Removed. + +2003-08-19 Gerd Moellmann <gerd@gnu.org> + + * s/freebsd.h [__FreeBSD_version >= 400000]: Define TERMINFO, + use -lncurses. + + * term.c (term_init): Use a buffer of size 4096 for tgetent since + FreeBSD returns something longer than 2044. Abort if the end of + the buffer is overwritten. + +2003-08-19 Miles Bader <miles@gnu.org> + + * xterm.c (x_term_init): Correctly use result of Ffile_readable_p. + +2003-08-19 Gerd Moellmann <gerd@gnu.org> + + * alloc.c (lisp_align_malloc): Check for memory full when + allocating ablocks, which also avoids freeing a pointer into an + ablocks structure. + + * puresize.h (BASE_PURESIZE): Increase to 1100000. + + * buffer.c (Fmove_overlay): Set overlay's next pointer unconditionally. + +2003-08-16 Richard M. Stallman <rms@gnu.org> + + * editfns.c (Fencode_time): Doc fix. + +2003-08-16 David Ponce <david@dponce.com> + + * fileio.c (Fwrite_region): Fix conditional expression to issue + the right message. + +2003-08-16 Juri Linkov <juri@jurta.org> (tiny change) + + * syntax.c (Fforward_word): Argument changed to optional. + Set default value to 1. + +2003-08-15 Kenichi Handa <handa@m17n.org> + + * xfaces.c (better_font_p): Prefer a real scalable font; i.e. not + what autoscaled. + (best_matching_font): Once we find a better scalable font, set + non_scalable_has_exact_height_p to 1. + (try_font_list): Call try_alternative_families to try any family + with the given registry. + +2003-08-09 Andreas Schwab <schwab@suse.de> + + * alloc.c (mark_object): Handle Lisp_Misc_Save_Value. + + * print.c (print_string): Fix printing of multibyte string with + nontrivial printcharfun. + 2003-07-31 Jan Dj,Ad(Brv <jan.h.d@swipnet.se> * xfns.c (xg_set_icon): Rewrite to compile with GTK 2.0 and 2.2. @@ -38,8 +2738,7 @@ 2003-07-28 KOBAYASHI Yasuhiro <kobayays@otsukakj.co.jp> (tiny change) - * xfns.c (xic_set_preeditarea): Add the left fringe width to - spot.x. + * xfns.c (xic_set_preeditarea): Add the left fringe width to spot.x. 2003-07-22 Stefan Monnier <monnier@cs.yale.edu> @@ -600,7 +3299,7 @@ * gtkutil.c: Include keyboard.h, charset.h, coding.h. (xg_create_frame_widgets): Use ENCODE_UTF_8. - * xterm.c (Qutf_8): Moved to coding.c + * xterm.c (Qutf_8): Move to coding.c * xmenu.c (ENCODE_MENU_STRING): New. (list_of_panes, list_of_items, digest_single_submenu, xmenu_show): @@ -1181,11 +3880,11 @@ (draw_fringe_bitmap): Rework to handle per-window fringes and new fringe vs. display margin position. (hscroll_window_tree): Use window_box_width instead of window_box. - (redisplay_window): Adapt to per-window scroll bars. - (draw_glyphs): Rework to handle per-window fringes and scroll + (redisplay_window): Adapt to per-window scroll bars. + (draw_glyphs): Rework to handle per-window fringes and scroll bars, and new fringe vs. display margin position. Use WINDOW_LEFT_EDGE_X, WINDOW_TOTAL_WIDTH, and window_box_left. - (x_clear_end_of_line): Adapt to per-window fringes and scroll + (x_clear_end_of_line): Adapt to per-window fringes and scroll bars, and new fringe vs. display margin position. Fix bug which increased total width of full_width rows by width of scroll bars although window's total width already includes that. @@ -2252,7 +4951,7 @@ (w32_draw_window_cursor): New W32-specific functions for RIF. (w32_redisplay_interface): Add new members. - * w32gui.h (No_Cursor): Define as 0 for W32. + * w32gui.h (No_Cursor): Define as 0 for W32. (XRectangle): Add X compatible rectangle type. (NativeRectangle): Declare as RECT for W32. (CONVERT_TO_XRECT, CONVERT_FROM_XRECT, STORE_NATIVE_RECT): New macros. @@ -3340,7 +6039,7 @@ * lisp.h: Declare Vx_resource_name extern. - * keyboard.c (kbd_buffer_get_event): Check MENU_BAR_ACTIVATE_EVENT + * keyboard.c (kbd_buffer_get_event): Check MENU_BAR_ACTIVATE_EVENT for USE_GTK. (make_lispy_event): Check MENU_BAR_EVENT for USE_GTK. @@ -3727,12 +6426,12 @@ Its primary purpose at this time is to initialize the global variable track_mouse_event_fn. - * w32fns.c (w32_wnd_proc): Remove initialization of + * w32fns.c (w32_wnd_proc): Remove initialization of track_mouse_event_fn from the handler for the WM_SETFOCUS message. * w32fns.c (syms_of_w32fns): Call globals_of_w32fns. - * w32menu.c (globals_of_w32menu): New function. Used to + * w32menu.c (globals_of_w32menu): New function. Used to initialize those global variables that must always be initialized on startup even when the global variable initialized is non zero. Its primary purpose at this time is to initialize the global @@ -8919,7 +11618,7 @@ 2001-12-03 Pavel Jan,Am(Bk <Pavel@Janik.cz> - * xdisp.c (syms_of_xdisp): Make `tool-bar-button-relief` an option. + * xdisp.c (syms_of_xdisp): Make `tool-bar-button-relief' an option. 2001-12-02 Pavel Jan,Am(Bk <Pavel@Janik.cz> @@ -10512,3 +13211,5 @@ See ChangeLog.9 for earlier changes. Copyright (C) 2001, 2002 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted provided the copyright notice and this notice are preserved. + +;;; arch-tag: 5dcc435f-4038-4141-b3bf-5be51cd76bd4 diff --git a/src/ChangeLog.1 b/src/ChangeLog.1 index 3ffbd61f607..94f1039f71e 100644 --- a/src/ChangeLog.1 +++ b/src/ChangeLog.1 @@ -3525,3 +3525,5 @@ Copyright (C) 1985, 1986 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted provided the copyright notice and this notice are preserved. + +;;; arch-tag: 2d2c1086-b0a5-437c-bc58-fb38ce2e0f9b diff --git a/src/ChangeLog.2 b/src/ChangeLog.2 index edbbfd3a7c0..430cbc0f9da 100644 --- a/src/ChangeLog.2 +++ b/src/ChangeLog.2 @@ -4774,3 +4774,5 @@ See ChangeLog.1 for earlier changes. Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted provided the copyright notice and this notice are preserved. + +;;; arch-tag: 3334fc8a-ec24-4601-99fc-4c8adc2b31bb diff --git a/src/ChangeLog.3 b/src/ChangeLog.3 index a93f4ab9825..73f87793541 100644 --- a/src/ChangeLog.3 +++ b/src/ChangeLog.3 @@ -16534,3 +16534,5 @@ See ChangeLog.2 for earlier changes. Copyright (C) 1993 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted provided the copyright notice and this notice are preserved. + +;;; arch-tag: 136a8e5c-4f83-403b-9132-874f1c47f8a9 diff --git a/src/ChangeLog.4 b/src/ChangeLog.4 index 36ec0081a62..b3d40b96b6c 100644 --- a/src/ChangeLog.4 +++ b/src/ChangeLog.4 @@ -6906,3 +6906,5 @@ See ChangeLog.3 for earlier changes. Copyright (C) 1993, 1994 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted provided the copyright notice and this notice are preserved. + +;;; arch-tag: 2e44924a-e45a-4129-ad93-1f7bb410b609 diff --git a/src/ChangeLog.5 b/src/ChangeLog.5 index 1f20b6812f7..20fc4887084 100644 --- a/src/ChangeLog.5 +++ b/src/ChangeLog.5 @@ -7147,3 +7147,5 @@ See ChangeLog.4 for earlier changes. Copyright (C) 1994, 1995 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted provided the copyright notice and this notice are preserved. + +;;; arch-tag: aea244d6-d513-4b51-8dba-5ecdf1aa5875 diff --git a/src/ChangeLog.6 b/src/ChangeLog.6 index 3cf30f682e3..52e48cac275 100644 --- a/src/ChangeLog.6 +++ b/src/ChangeLog.6 @@ -5365,3 +5365,5 @@ See ChangeLog.5 for earlier changes. Copyright (C) 1995, 1996 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted provided the copyright notice and this notice are preserved. + +;;; arch-tag: 66a98e1c-2268-45e8-8a57-286b9c85a4e9 diff --git a/src/ChangeLog.7 b/src/ChangeLog.7 index 99631e5eefa..f1a29903715 100644 --- a/src/ChangeLog.7 +++ b/src/ChangeLog.7 @@ -11101,3 +11101,5 @@ See ChangeLog.6 for earlier changes. Copyright (C) 1997, 1998 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted provided the copyright notice and this notice are preserved. + +;;; arch-tag: 3b03e091-1123-4031-b67d-41683932cc48 diff --git a/src/ChangeLog.8 b/src/ChangeLog.8 index 1c2f7820bb5..91fcdd1c899 100644 --- a/src/ChangeLog.8 +++ b/src/ChangeLog.8 @@ -13994,3 +13994,5 @@ See ChangeLog.7 for earlier changes. Copyright (C) 1999 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted provided the copyright notice and this notice are preserved. + +;;; arch-tag: 4d73444a-8f6e-4255-92a6-d3abc438b8d3 diff --git a/src/ChangeLog.9 b/src/ChangeLog.9 index 224b8384f5a..9ce75696f5a 100644 --- a/src/ChangeLog.9 +++ b/src/ChangeLog.9 @@ -13297,3 +13297,5 @@ See ChangeLog.8 for earlier changes. Copyright (C) 2001, 2002 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted provided the copyright notice and this notice are preserved. + +;;; arch-tag: 38875948-6e89-4f08-b0ca-ff328f1e8b72 diff --git a/src/Makefile.in b/src/Makefile.in index 3a4b0cf0ec2..5e6f1e62225 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,5 +1,5 @@ # Makefile for GNU Emacs. -# Copyright (C) 1985, 87, 88, 93, 94, 95, 99, 2000, 2001, 2003 +# Copyright (C) 1985, 87, 88, 93, 94, 95, 99, 2000, 01, 03, 2004 # Free Software Foundation, Inc. # This file is part of GNU Emacs. @@ -305,14 +305,17 @@ ALL_CFLAGS=-Demacs -DHAVE_CONFIG_H $(TOOLKIT_DEFINES) $(MYCPPFLAGS) -I. -I${srcd #endif #ifdef HAVE_X_WINDOWS + +XOBJ= xterm.o xfns.o xselect.o xrdb.o fontset.o xsmfns.o fringe.o image.o + #ifdef HAVE_MENUS -/* Include xmenu.o in the list of X object files. */ +#ifndef HAVE_CARBON +XMENU_OBJ = xmenu.o +#endif #ifdef USE_GTK -XOBJ= xterm.o xfns.o xselect.o xrdb.o fontset.o xsmfns.o gtkutil.o -#else -XOBJ= xterm.o xfns.o xselect.o xrdb.o fontset.o xsmfns.o +GTK_OBJ= gtkutil.o #endif /* The X Menu stuff is present in the X10 distribution, but missing @@ -332,9 +335,7 @@ LIBXMENU= -lXMenu #else /* not HAVE_MENUS */ -/* Otherwise, omit xmenu.o from the list of X object files, and - don't worry about the menu library at all. */ -XOBJ= xterm.o xfns.o xselect.o xrdb.o fontset.o xsmfns.o +/* Otherwise, don't worry about the menu library at all. */ LIBXMENU= #endif /* not HAVE_MENUS */ @@ -447,6 +448,10 @@ LIBX= $(LIBXMENU) $(X11_LDFLAGS) $(LIBXT) LIBTIFF LIBJPEG LIBPNG LIBGIF LIBXPM L #else /* not HAVE_X11 */ LIBX= $(LIBXMENU) LD_SWITCH_X_SITE -lX10 LIBX10_MACHINE LIBX10_SYSTEM #endif /* not HAVE_X11 */ +#else /* not HAVE_X_WINDOWS */ +#if defined(HAVE_MENUS) && !defined(HAVE_CARBON) +XMENU_OBJ = xmenu.o +#endif #endif /* not HAVE_X_WINDOWS */ LIBSOUND= @LIBSOUND@ @@ -559,21 +564,22 @@ MSDOS_OBJ = dosfns.o msdos.o w16select.o #endif #endif +#ifdef CYGWIN +CYGWIN_OBJ = sheap.o +#endif + #ifdef HAVE_CARBON mac = $(dot)$(dot)/mac/ -XMENU_OBJ = -MAC_OBJ = mac.o macterm.o macfns.o macmenu.o fontset.o +MAC_OBJ = mac.o macterm.o macfns.o macmenu.o fontset.o fringe.o image.o emacsapp = $(PWD)/$(mac)Emacs.app/ emacsappsrc = ${srcdir}/../mac/Emacs.app/ -#else -XMENU_OBJ = xmenu.o #endif /* lastfile must follow all files whose initialized data areas should be dumped as pure by dump-emacs. */ obj= dispnew.o frame.o scroll.o xdisp.o $(XMENU_OBJ) window.o \ charset.o coding.o category.o ccl.o character.o chartab.o \ - cm.o term.o xfaces.o $(XOBJ) \ + cm.o term.o xfaces.o $(XOBJ) $(GTK_OBJ)\ emacs.o keyboard.o macros.o keymap.o sysdep.o \ buffer.o filelock.o insdel.o marker.o \ minibuf.o fileio.o dired.o filemode.o \ @@ -584,7 +590,7 @@ obj= dispnew.o frame.o scroll.o xdisp.o $(XMENU_OBJ) window.o \ process.o callproc.o \ region-cache.o sound.o atimer.o \ doprnt.o strftime.o intervals.o textprop.o composite.o md5.o \ - $(MSDOS_OBJ) $(MAC_OBJ) + $(MSDOS_OBJ) $(MAC_OBJ) $(CYGWIN_OBJ) /* Object files used on some machine or other. These go in the DOC file on all machines @@ -641,7 +647,12 @@ widgetobj= /* define otherobj as list of object files that make-docfile should not be told about. */ +#ifdef CYGWIN +/* Cygwin differs because of its unexec(). */ +otherobj= $(termcapobj) $(gmallocobj) $(rallocobj) lastfile.o vm-limit.o $(allocaobj) $(widgetobj) $(LIBOBJS) +#else otherobj= $(termcapobj) lastfile.o $(mallocobj) $(allocaobj) $(widgetobj) $(LIBOBJS) +#endif #ifdef HAVE_MOUSE #define MOUSE_SUPPORT ${lispsource}mouse.elc \ @@ -722,6 +733,7 @@ lisp= \ ${lispsource}language/cyrillic.el \ ${lispsource}language/indian.el \ ${lispsource}language/devanagari.el \ + ${lispsource}language/kannada.el \ ${lispsource}language/malayalam.el \ ${lispsource}language/tamil.el \ ${lispsource}language/english.el \ @@ -802,6 +814,7 @@ shortlisp= \ ../lisp/language/cyrillic.el \ ../lisp/language/indian.el \ ../lisp/language/devanagari.el \ + ../lisp/language/kannada.el \ ../lisp/language/malayalam.el \ ../lisp/language/tamil.el \ ../lisp/language/english.el \ @@ -926,11 +939,6 @@ prefix-args${EXEEXT}: prefix-args.c $(config_h) #define OLDXMENU_OPTIONS #endif -/* Don't lose if this was not defined. */ -#ifndef LWLIB_OPTIONS -#define LWLIB_OPTIONS -#endif - #if defined (HAVE_X_WINDOWS) && defined (HAVE_X11) && defined (HAVE_MENUS) /* We use stamp-xmenu with these two deps @@ -954,7 +962,7 @@ C_SWITCH_X_SITE_1 = C_SWITCH_X_SITE C_SWITCH_X_MACHINE_1 = C_SWITCH_X_MACHINE C_SWITCH_X_SYSTEM_1 = C_SWITCH_X_SYSTEM really-lwlib: - cd ${lwlibdir}; ${MAKE} ${MFLAGS} LWLIB_OPTIONS \ + cd ${lwlibdir}; ${MAKE} ${MFLAGS} \ CC='${CC}' CFLAGS='${CFLAGS}' MAKE='${MAKE}' \ "C_SWITCH_X_SITE=$(C_SWITCH_X_SITE_1)" \ "C_SWITCH_X_MACHINE=$(C_SWITCH_X_MACHINE_1)" \ @@ -1005,40 +1013,10 @@ stamp-oldxmenu: exit 1 /* Some machines have alloca built-in. - They should define HAVE_ALLOCA, or may just let alloca.s - be used but generate no code. - Some have it written in assembler in alloca.s. + They should define HAVE_ALLOCA. Some use the C version in alloca.c (these define C_ALLOCA in config.h). */ - -#ifdef C_ALLOCA -/* We could put something in alloca.c to #define free and malloc - whenever emacs was #defined, but that's not appropriate for all - users of alloca in Emacs. Check out ../lib-src/getopt.c. */ -alloca.o : alloca.c - $(CC) -c $(CPPFLAGS) -DEMACS_FREE=xfree -DDO_BLOCK_INPUT \ - $(ALL_CFLAGS) ${srcdir}/alloca.c -#else -#ifndef HAVE_ALLOCA -alloca.o : alloca.s $(config_h) -/* $(CPP) is cc -E, which may get confused by filenames - that do not end in .c. So copy file to a safe name. */ - -rm -f allocatem.c - cp ${srcdir}/alloca.s allocatem.c -/* Remove any ^L, blank lines, and preprocessor comments, - since some assemblers barf on them. Use a different basename for the - output file, since some stupid compilers (Green Hill's) use that - name for the intermediate assembler file. */ - $(CPP) $(CPPFLAGS) $(ALL_CFLAGS) allocatem.c | \ - sed -e 's///' -e 's/^#.*//' | \ - sed -n -e '/^..*$$/p' > allocax.s - -rm -f alloca.o -/* Xenix, in particular, needs to run assembler via cc. */ - $(CC) -c allocax.s - mv allocax.o alloca.o - -rm -f allocax.s allocatem.c -#endif /* HAVE_ALLOCA */ -#endif /* ! defined (C_ALLOCA) */ +alloca.o: alloca.c blockinput.h atimer.h /* Nearly all the following files depend on lisp.h, but it is not included as a dependency because @@ -1065,8 +1043,7 @@ character.o: character.c character.h buffer.h charset.h composite.h disptab.h \ charset.o: charset.c charset.h character.h buffer.h coding.h composite.h \ disptab.h $(config_h) chartab.o: charset.h character.h $(config.h) -coding.o: coding.c coding.h ccl.h buffer.h character.h charset.h composite.h \ - $(config_h) +coding.o: coding.c coding.h ccl.h buffer.h character.h charset.h intervals.h composite.h window.h $(config_h) cm.o: cm.c cm.h termhooks.h $(config_h) cmds.o: cmds.c syntax.h buffer.h character.h commands.h window.h $(config_h) \ msdos.h dispextern.h @@ -1086,7 +1063,8 @@ dosfns.o: buffer.h termchar.h termhooks.h frame.h msdos.h dosfns.h $(config_h) editfns.o: editfns.c window.h buffer.h systime.h $(INTERVAL_SRC) character.h \ coding.h dispextern.h $(config_h) emacs.o: emacs.c commands.h systty.h syssignal.h blockinput.h process.h \ - termhooks.h buffer.h atimer.h systime.h $(INTERVAL_SRC) $(config_h) + termhooks.h buffer.h atimer.h systime.h $(INTERVAL_SRC) $(config_h) \ + window.h keyboard.h keymap.h fileio.o: fileio.c window.h buffer.h systime.h $(INTERVAL_SRC) character.h \ coding.h ccl.h msdos.h dispextern.h $(config_h) filelock.o: filelock.c buffer.h character.h charset.h coding.h systime.h \ @@ -1095,9 +1073,12 @@ filemode.o: filemode.c $(config_h) frame.o: frame.c xterm.h window.h frame.h termhooks.h commands.h keyboard.h \ blockinput.h atimer.h systime.h buffer.h character.h fontset.h \ msdos.h dosfns.h dispextern.h $(config_h) +fringe.o: fringe.c dispextern.h frame.h window.h buffer.h $(config_h) fontset.o: dispextern.h fontset.h fontset.c ccl.h buffer.h character.h \ charset.h frame.h keyboard.h $(config_h) getloadavg.o: getloadavg.c $(config_h) +image.o: image.c frame.h window.h dispextern.h blockinput.h atimer.h \ + systime.h xterm.h w32term.h w32gui.h macterm.h macgui.h $(config_h) indent.o: indent.c frame.h window.h indent.h buffer.h $(config_h) termchar.h \ termopts.h disptab.h region-cache.h character.h category.h composite.h \ dispextern.h keyboard.h @@ -1123,7 +1104,7 @@ minibuf.o: minibuf.c syntax.h dispextern.h frame.h window.h keyboard.h \ mktime.o: mktime.c $(config_h) msdos.o: msdos.c msdos.h dosfns.h systime.h termhooks.h dispextern.h frame.h \ termopts.h termchar.h character.h coding.h ccl.h disptab.h window.h \ - keyboard.h $(config_h) + keyboard.h intervals.h $(config_h) process.o: process.c process.h buffer.h window.h termhooks.h termopts.h \ commands.h syssignal.h systime.h systty.h syswait.h frame.h dispextern.h \ blockinput.h atimer.h charset.h coding.h ccl.h msdos.h composite.h \ @@ -1172,7 +1153,7 @@ xfns.o: xfns.c buffer.h frame.h window.h keyboard.h xterm.h dispextern.h \ character.h charset.h coding.h gtkutil.h $(config_h) termhooks.h xmenu.o: xmenu.c xterm.h termhooks.h window.h dispextern.h frame.h buffer.h \ charset.h keyboard.h $(srcdir)/../lwlib/lwlib.h blockinput.h atimer.h \ - systime.h gtkutil.h msdos.h $(config_h) coding.h + systime.h gtkutil.h msdos.h coding.h $(config_h) xterm.o: xterm.c xterm.h termhooks.h termopts.h termchar.h window.h buffer.h \ dispextern.h frame.h disptab.h blockinput.h atimer.h systime.h syssignal.h \ keyboard.h gnu.h character.h charset.h ccl.h fontset.h composite.h \ @@ -1180,9 +1161,10 @@ xterm.o: xterm.c xterm.h termhooks.h termopts.h termchar.h window.h buffer.h \ xselect.o: xselect.c process.h dispextern.h frame.h xterm.h blockinput.h \ buffer.h atimer.h systime.h $(config_h) xrdb.o: xrdb.c $(config_h) epaths.h -xsmfns.o: xsmfns.c $(config_h) systime.h sysselect.h termhooks.h +xsmfns.o: xsmfns.c $(config_h) systime.h sysselect.h termhooks.h xterm.h \ + lisp.h termopts.h gtkutil.o: gtkutil.c gtkutil.h xterm.h lisp.h frame.h $(config_h) \ - blockinput.h window.h atimer.h termhooks.h coding.h + blockinput.h window.h atimer.h termhooks.h keyboard.h charset.h coding.h hftctl.o: hftctl.c $(config_h) sound.o: sound.c dispextern.h $(config_h) @@ -1193,14 +1175,14 @@ atimer.o: atimer.c atimer.h systime.h $(config_h) alloc.o: alloc.c process.h frame.h window.h buffer.h puresize.h syssignal.h keyboard.h \ blockinput.h atimer.h systime.h character.h dispextern.h $(config_h) \ $(INTERVAL_SRC) -bytecode.o: bytecode.c buffer.h syntax.h character.h $(config_h) +bytecode.o: bytecode.c buffer.h syntax.h character.h window.h $(config_h) data.o: data.c buffer.h puresize.h character.h syssignal.h keyboard.h \ $(config_h) eval.o: eval.c commands.h keyboard.h blockinput.h atimer.h systime.h \ - $(config_h) + dispextern.h $(config_h) floatfns.o: floatfns.c $(config_h) fns.o: fns.c commands.h $(config_h) frame.h buffer.h character.h keyboard.h \ - frame.h window.h dispextern.h $(INTERVAL_SRC) coding.h + frame.h window.h dispextern.h $(INTERVAL_SRC) coding.h md5.h print.o: print.c process.h frame.h window.h buffer.h keyboard.h character.h \ $(config_h) dispextern.h msdos.h composite.h lread.o: lread.c commands.h keyboard.h buffer.h epaths.h character.h \ @@ -1341,3 +1323,5 @@ bootstrap-emacs${EXEEXT}: temacs${EXEEXT} mv -f emacs${EXEEXT} bootstrap-emacs${EXEEXT} #endif /* ! defined (CANNOT_DUMP) */ +/* arch-tag: 8e915ae5-d15d-4617-8c41-c5c267a23b00 + (do not change this comment) */ diff --git a/src/abbrev.c b/src/abbrev.c index e3e0e28210b..54ea8f1128e 100644 --- a/src/abbrev.c +++ b/src/abbrev.c @@ -356,10 +356,13 @@ Returns the abbrev symbol, if expansion took place. */) { SET_PT (wordstart); - del_range_both (wordstart, wordstart_byte, wordend, wordend_byte, 1); - insert_from_string (expansion, 0, 0, SCHARS (expansion), SBYTES (expansion), 1); + del_range_both (PT, PT_BYTE, + wordend + (PT - wordstart), + wordend_byte + (PT_BYTE - wordstart_byte), + 1); + SET_PT (PT + whitecnt); if (uccount && !lccount) @@ -543,7 +546,8 @@ is inserted. Otherwise the description is an expression, a call to `define-abbrev-table', which would define the abbrev table NAME exactly as it is currently defined. -Abbrevs marked as "system abbrevs" are omitted. */) +Abbrevs marked as "system abbrevs" are normally omitted. However, if +READABLE is non-nil, they are listed. */) (name, readable) Lisp_Object name, readable; { @@ -696,3 +700,6 @@ the current abbrev table before abbrev lookup happens. */); defsubr (&Sinsert_abbrev_table_description); defsubr (&Sdefine_abbrev_table); } + +/* arch-tag: b721db69-f633-44a8-a361-c275acbdad7d + (do not change this comment) */ diff --git a/src/acldef.h b/src/acldef.h index cc4085c6aab..eee3e72a3e9 100644 --- a/src/acldef.h +++ b/src/acldef.h @@ -38,3 +38,6 @@ #define ACL$W_SIZE 8 #define ACL$B_TYPE 10 #define ACL$L_LIST 12 + +/* arch-tag: 7c11e99d-34df-41e8-98e2-20f152c4ad73 + (do not change this comment) */ diff --git a/src/alloc.c b/src/alloc.c index 8d74905728b..e427c1f5676 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -1,5 +1,5 @@ /* Storage allocation and gc for GNU Emacs Lisp interpreter. - Copyright (C) 1985, 86, 88, 93, 94, 95, 97, 98, 1999, 2000, 2001, 2002, 2003 + Copyright (C) 1985,86,88,93,94,95,97,98,1999,2000,01,02,03,2004 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -31,13 +31,6 @@ Boston, MA 02111-1307, USA. */ #include <signal.h> -/* GC_MALLOC_CHECK defined means perform validity checks of malloc'd - memory. Can do this only if using gmalloc.c. */ - -#if defined SYSTEM_MALLOC || defined DOUG_LEA_MALLOC -#undef GC_MALLOC_CHECK -#endif - /* This file is part of the core Lisp implementation, and thus must deal with the real data structures. If the Lisp implementation is replaced, this file likely will not be used. */ @@ -56,6 +49,13 @@ Boston, MA 02111-1307, USA. */ #include "syssignal.h" #include <setjmp.h> +/* GC_MALLOC_CHECK defined means perform validity checks of malloc'd + memory. Can do this only if using gmalloc.c. */ + +#if defined SYSTEM_MALLOC || defined DOUG_LEA_MALLOC +#undef GC_MALLOC_CHECK +#endif + #ifdef HAVE_UNISTD_H #include <unistd.h> #else @@ -598,6 +598,7 @@ lisp_malloc (nbytes, type) val = (void *) malloc (nbytes); +#ifndef USE_LSB_TAG /* If the memory just allocated cannot be addressed thru a Lisp object's pointer, and it needs to be, that's equivalent to running out of memory. */ @@ -612,6 +613,7 @@ lisp_malloc (nbytes, type) val = 0; } } +#endif #if GC_MARK_STACK && !defined GC_MALLOC_CHECK if (val && type != MEM_TYPE_NON_LISP) @@ -756,6 +758,11 @@ lisp_align_malloc (nbytes, type) #else base = malloc (ABLOCKS_BYTES); abase = ALIGN (base, BLOCK_ALIGN); + if (base == 0) + { + UNBLOCK_INPUT; + memory_full (); + } #endif aligned = (base == abase); @@ -767,6 +774,7 @@ lisp_align_malloc (nbytes, type) mallopt (M_MMAP_MAX, MMAP_MAX_AREAS); #endif +#ifndef USE_LSB_TAG /* If the memory just allocated cannot be addressed thru a Lisp object's pointer, and it needs to be, that's equivalent to running out of memory. */ @@ -783,6 +791,7 @@ lisp_align_malloc (nbytes, type) memory_full (); } } +#endif /* Initialize the blocks and put them on the free list. Is `base' was not properly aligned, we can't use the last block. */ @@ -1099,8 +1108,9 @@ uninterrupt_malloc () struct interval_block { - struct interval_block *next; + /* Place `intervals' first, to preserve alignment. */ struct interval intervals[INTERVAL_BLOCK_SIZE]; + struct interval_block *next; }; /* Current interval block. Its `next' pointer points to older @@ -1338,8 +1348,9 @@ struct sblock struct string_block { - struct string_block *next; + /* Place `strings' first, to preserve alignment. */ struct Lisp_String strings[STRING_BLOCK_SIZE]; + struct string_block *next; }; /* Head and tail of the list of sblock structures holding Lisp string @@ -2120,8 +2131,10 @@ make_uninit_multibyte_string (nchars, nbytes) by GC are put on a free list to be reallocated before allocating any new float cells from the latest float_block. */ -#define FLOAT_BLOCK_SIZE \ - (((BLOCK_BYTES - sizeof (struct float_block *)) * CHAR_BIT) \ +#define FLOAT_BLOCK_SIZE \ + (((BLOCK_BYTES - sizeof (struct float_block *) \ + /* The compiler might add padding at the end. */ \ + - (sizeof (struct Lisp_Float) - sizeof (int))) * CHAR_BIT) \ / (sizeof (struct Lisp_Float) * CHAR_BIT + 1)) #define GETMARKBIT(block,n) \ @@ -2224,15 +2237,17 @@ make_float (float_value) new = (struct float_block *) lisp_align_malloc (sizeof *new, MEM_TYPE_FLOAT); new->next = float_block; + bzero ((char *) new->gcmarkbits, sizeof new->gcmarkbits); float_block = new; float_block_index = 0; n_float_blocks++; } - XSETFLOAT (val, &float_block->floats[float_block_index++]); + XSETFLOAT (val, &float_block->floats[float_block_index]); + float_block_index++; } XFLOAT_DATA (val) = float_value; - FLOAT_UNMARK (XFLOAT (val)); + eassert (!FLOAT_MARKED_P (XFLOAT (val))); consing_since_gc += sizeof (struct Lisp_Float); floats_consed++; return val; @@ -2340,17 +2355,19 @@ DEFUN ("cons", Fcons, Scons, 2, 2, 0, register struct cons_block *new; new = (struct cons_block *) lisp_align_malloc (sizeof *new, MEM_TYPE_CONS); + bzero ((char *) new->gcmarkbits, sizeof new->gcmarkbits); new->next = cons_block; cons_block = new; cons_block_index = 0; n_cons_blocks++; } - XSETCONS (val, &cons_block->conses[cons_block_index++]); + XSETCONS (val, &cons_block->conses[cons_block_index]); + cons_block_index++; } XSETCAR (val, car); XSETCDR (val, cdr); - CONS_UNMARK (XCONS (val)); + eassert (!CONS_MARKED_P (XCONS (val))); consing_since_gc += sizeof (struct Lisp_Cons); cons_cells_consed++; return val; @@ -2489,7 +2506,9 @@ allocate_vectorlike (len, type) /* Prevent mmap'ing the chunk. Lisp data may not be mmap'ed because mapped region contents are not preserved in a dumped Emacs. */ + BLOCK_INPUT; mallopt (M_MMAP_MAX, 0); + UNBLOCK_INPUT; #endif nbytes = sizeof *p + (len - 1) * sizeof p->contents[0]; @@ -2497,7 +2516,9 @@ allocate_vectorlike (len, type) #ifdef DOUG_LEA_MALLOC /* Back to a reasonable maximum of mmap'ed areas. */ + BLOCK_INPUT; mallopt (M_MMAP_MAX, MMAP_MAX_AREAS); + UNBLOCK_INPUT; #endif consing_since_gc += nbytes; @@ -2697,8 +2718,9 @@ usage: (make-byte-code ARGLIST BYTE-CODE CONSTANTS DEPTH &optional DOCSTRING INT struct symbol_block { - struct symbol_block *next; + /* Place `symbols' first, to preserve alignment. */ struct Lisp_Symbol symbols[SYMBOL_BLOCK_SIZE]; + struct symbol_block *next; }; /* Current symbol block and index of first unused Lisp_Symbol @@ -2756,7 +2778,8 @@ Its value and function definition are void, and its property list is nil. */) symbol_block_index = 0; n_symbol_blocks++; } - XSETSYMBOL (val, &symbol_block->symbols[symbol_block_index++]); + XSETSYMBOL (val, &symbol_block->symbols[symbol_block_index]); + symbol_block_index++; } p = XSYMBOL (val); @@ -2788,8 +2811,9 @@ Its value and function definition are void, and its property list is nil. */) struct marker_block { - struct marker_block *next; + /* Place `markers' first, to preserve alignment. */ union Lisp_Misc markers[MARKER_BLOCK_SIZE]; + struct marker_block *next; }; struct marker_block *marker_block; @@ -2834,7 +2858,8 @@ allocate_misc () marker_block_index = 0; n_marker_blocks++; } - XSETMISC (val, &marker_block->markers[marker_block_index++]); + XSETMISC (val, &marker_block->markers[marker_block_index]); + marker_block_index++; } consing_since_gc += sizeof (union Lisp_Misc); @@ -3369,6 +3394,7 @@ live_string_p (m, p) must not be on the free-list. */ return (offset >= 0 && offset % sizeof b->strings[0] == 0 + && offset < (STRING_BLOCK_SIZE * sizeof b->strings[0]) && ((struct Lisp_String *) p)->data != NULL); } else @@ -3393,8 +3419,8 @@ live_cons_p (m, p) one of the unused cells in the current cons block, and not be on the free-list. */ return (offset >= 0 - && offset < (CONS_BLOCK_SIZE * sizeof b->conses[0]) && offset % sizeof b->conses[0] == 0 + && offset < (CONS_BLOCK_SIZE * sizeof b->conses[0]) && (b != cons_block || offset / sizeof b->conses[0] < cons_block_index) && !EQ (((struct Lisp_Cons *) p)->car, Vdead)); @@ -3422,6 +3448,7 @@ live_symbol_p (m, p) and not be on the free-list. */ return (offset >= 0 && offset % sizeof b->symbols[0] == 0 + && offset < (SYMBOL_BLOCK_SIZE * sizeof b->symbols[0]) && (b != symbol_block || offset / sizeof b->symbols[0] < symbol_block_index) && !EQ (((struct Lisp_Symbol *) p)->function, Vdead)); @@ -3447,8 +3474,8 @@ live_float_p (m, p) /* P must point to the start of a Lisp_Float and not be one of the unused cells in the current float block. */ return (offset >= 0 - && offset < (FLOAT_BLOCK_SIZE * sizeof b->floats[0]) && offset % sizeof b->floats[0] == 0 + && offset < (FLOAT_BLOCK_SIZE * sizeof b->floats[0]) && (b != float_block || offset / sizeof b->floats[0] < float_block_index)); } @@ -3475,6 +3502,7 @@ live_misc_p (m, p) and not be on the free-list. */ return (offset >= 0 && offset % sizeof b->markers[0] == 0 + && offset < (MARKER_BLOCK_SIZE * sizeof b->markers[0]) && (b != marker_block || offset / sizeof b->markers[0] < marker_block_index) && ((union Lisp_Misc *) p)->u_marker.type != Lisp_Misc_Free); @@ -4009,6 +4037,9 @@ pure_alloc (size, type) int type; { POINTER_TYPE *result; +#ifdef USE_LSB_TAG + size_t alignment = (1 << GCTYPEBITS); +#else size_t alignment = sizeof (EMACS_INT); /* Give Lisp_Floats an extra alignment. */ @@ -4020,6 +4051,7 @@ pure_alloc (size, type) alignment = sizeof (struct Lisp_Float); #endif } +#endif again: result = ALIGN (purebeg + pure_bytes_used, alignment); @@ -4155,12 +4187,13 @@ Does not copy symbols. Copies strings without text properties. */) else if (COMPILEDP (obj) || VECTORP (obj)) { register struct Lisp_Vector *vec; - register int i, size; + register int i; + EMACS_INT size; size = XVECTOR (obj)->size; if (size & PSEUDOVECTOR_FLAG) size &= PSEUDOVECTOR_SIZE_MASK; - vec = XVECTOR (make_pure_vector ((EMACS_INT) size)); + vec = XVECTOR (make_pure_vector (size)); for (i = 0; i < size; i++) vec->contents[i] = Fpurecopy (XVECTOR (obj)->contents[i]); if (COMPILEDP (obj)) @@ -4446,13 +4479,6 @@ returns nil, because real GC can't be done. */) /* Clear the mark bits that we set in certain root slots. */ -#if (GC_MARK_STACK == GC_USE_GCPROS_AS_BEFORE \ - || GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES) - { - register struct gcpro *tail; - } -#endif - unmark_byte_stack (); VECTOR_UNMARK (&buffer_defaults); VECTOR_UNMARK (&buffer_local_symbols); diff --git a/src/alloca.c b/src/alloca.c index 4b574374bff..e8c8319adc4 100644 --- a/src/alloca.c +++ b/src/alloca.c @@ -36,7 +36,6 @@ #endif #ifdef DO_BLOCK_INPUT -# include "lisp.h" # include "blockinput.h" #endif @@ -58,7 +57,10 @@ you lose -- must know STACK_DIRECTION at compile-time /* Using #error here is not wise since this file should work for - old and obscure compilers. */ + old and obscure compilers. + + As far as I know, using it is OK if it's indented -- at least for + pcc-based processors. -- fx */ # endif /* STACK_DIRECTION undefined */ # endif /* static */ # endif /* emacs */ @@ -73,38 +75,32 @@ long i00afunc (); # define ADDRESS_FUNCTION(arg) &(arg) # endif -# ifdef POINTER_TYPE +# ifndef POINTER_TYPE +# ifdef __STDC__ +# define POINTER_TYPE void +# else +# define POINTER_TYPE char +# endif +# endif typedef POINTER_TYPE *pointer; -# else /* not POINTER_TYPE */ -# if __STDC__ -typedef void *pointer; -# else /* not __STDC__ */ -typedef char *pointer; -# endif /* not __STDC__ */ -# endif /* not POINTER_TYPE */ # ifndef NULL # define NULL 0 # endif -/* Different portions of Emacs need to call different versions of - malloc. The Emacs executable needs alloca to call xmalloc, because - ordinary malloc isn't protected from input signals. On the other - hand, the utilities in lib-src need alloca to call malloc; some of - them are very simple, and don't have an xmalloc routine. - - Non-Emacs programs expect this to call xmalloc. +/* The Emacs executable needs alloca to call xmalloc, because ordinary + malloc isn't protected from input signals. xmalloc also checks for + out-of-memory errors, so we should use it generally. Callers below should use malloc. */ -# ifdef emacs -# undef malloc -# define malloc xmalloc -# ifdef EMACS_FREE -# define free EMACS_FREE -# endif -# endif -extern pointer malloc (); +# undef malloc +# define malloc xmalloc +# undef free +# define free xfree + +void *xmalloc _P ((size_t)); +void xfree _P ((void *)); /* Define STACK_DIRECTION if you know the direction of stack growth for your system; otherwise it will be automatically @@ -229,8 +225,8 @@ alloca (size) /* Allocate combined header + user data storage. */ { - register pointer new = malloc (sizeof (header) + size); /* Address of header. */ + register pointer new = malloc (sizeof (header) + size); if (new == 0) abort(); @@ -516,3 +512,6 @@ i00afunc (long address) # endif /* no alloca */ #endif /* not GCC version 2 */ + +/* arch-tag: 5c9901c8-3cd4-453e-bd66-d9035a175ee3 + (do not change this comment) */ diff --git a/src/atimer.c b/src/atimer.c index 25b48c5857a..2ddc7427f56 100644 --- a/src/atimer.c +++ b/src/atimer.c @@ -19,13 +19,13 @@ the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <config.h> -#include <lisp.h> #include <signal.h> +#include <stdio.h> +#include <lisp.h> #include <syssignal.h> #include <systime.h> #include <blockinput.h> #include <atimer.h> -#include <stdio.h> #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -433,3 +433,6 @@ init_atimer () pending_atimers = 0; signal (SIGALRM, alarm_signal_handler); } + +/* arch-tag: e6308261-eec6-404b-89fb-6e5909518d70 + (do not change this comment) */ diff --git a/src/atimer.h b/src/atimer.h index 4a487cdbb30..3ecc97e5511 100644 --- a/src/atimer.h +++ b/src/atimer.h @@ -21,6 +21,13 @@ Boston, MA 02111-1307, USA. */ #ifndef EMACS_ATIMER_H #define EMACS_ATIMER_H +/* Declare the prototype for a general external function. */ +#if defined (PROTOTYPES) || defined (WINDOWSNT) +#define P_(proto) proto +#else +#define P_(proto) () +#endif + #include "systime.h" /* for EMACS_TIME */ /* Forward declaration. */ @@ -82,3 +89,6 @@ void run_all_atimers P_ ((void)); Lisp_Object unwind_stop_other_atimers P_ ((Lisp_Object)); #endif /* EMACS_ATIMER_H */ + +/* arch-tag: 02c7c1c8-45bd-4222-b874-4ca44662f60b + (do not change this comment) */ diff --git a/src/blockinput.h b/src/blockinput.h index c5485fa4801..eba192c9863 100644 --- a/src/blockinput.h +++ b/src/blockinput.h @@ -102,3 +102,6 @@ extern int pending_atimers; extern void reinvoke_input_signal (); #endif /* EMACS_BLOCKINPUT_H */ + +/* arch-tag: 51a9ec86-945a-4966-8f04-2d1341250e03 + (do not change this comment) */ diff --git a/src/buffer.c b/src/buffer.c index b7efdbe5504..4c7e709adb5 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1,5 +1,5 @@ /* Buffer manipulation primitives for GNU Emacs. - Copyright (C) 1985,86,87,88,89,93,94,95,97,98, 1999, 2000, 2001, 02, 2003 + Copyright (C) 1985,86,87,88,89,93,94,95,97,98, 1999, 2000, 2001, 02, 03, 2004 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -67,7 +67,7 @@ struct buffer *all_buffers; Setting the default value also goes through the alist of buffers and stores into each buffer that does not say it has a local value. */ -struct buffer buffer_defaults; +DECL_ALIGN (struct buffer, buffer_defaults); /* A Lisp_Object pointer to the above, used for staticpro */ @@ -89,10 +89,6 @@ static Lisp_Object Vbuffer_defaults; If a slot is -2, then there is no DEFVAR_PER_BUFFER for it, but there is a default value which is copied into each buffer. - If a slot in this structure is negative, then even though there may - be a DEFVAR_PER_BUFFER for the slot, there is no default value for it; - and the corresponding slot in buffer_defaults is not used. - If a slot in this structure corresponding to a DEFVAR_PER_BUFFER is zero, that is a bug */ @@ -101,7 +97,8 @@ struct buffer buffer_local_flags; /* This structure holds the names of symbols whose values may be buffer-local. It is indexed and accessed in the same way as the above. */ -struct buffer buffer_local_symbols; +DECL_ALIGN (struct buffer, buffer_local_symbols); + /* A Lisp_Object pointer to the above, used for staticpro */ static Lisp_Object Vbuffer_local_symbols; @@ -525,7 +522,7 @@ DEFUN ("make-indirect-buffer", Fmake_indirect_buffer, Smake_indirect_buffer, 2, 3, "bMake indirect buffer (to buffer): \nBName of indirect buffer: ", doc: /* Create and return an indirect buffer for buffer BASE-BUFFER, named NAME. -BASE-BUFFER should be an existing buffer (or buffer name). +BASE-BUFFER should be a live buffer, or the name of an existing buffer. NAME should be a string which is not the name of an existing buffer. Optional argument CLONE non-nil means preserve BASE-BUFFER's state, such as major and minor modes, in the indirect buffer. @@ -533,16 +530,20 @@ CLONE nil means the indirect buffer's state is reset to default values. */) (base_buffer, name, clone) Lisp_Object base_buffer, name, clone; { - Lisp_Object buf; + Lisp_Object buf, tem; struct buffer *b; + CHECK_STRING (name); buf = Fget_buffer (name); if (!NILP (buf)) error ("Buffer name `%s' is in use", SDATA (name)); + tem = base_buffer; base_buffer = Fget_buffer (base_buffer); if (NILP (base_buffer)) - error ("No such buffer: `%s'", SDATA (name)); + error ("No such buffer: `%s'", SDATA (tem)); + if (NILP (XBUFFER (base_buffer)->name)) + error ("Base buffer has been killed"); if (SCHARS (name) == 0) error ("Empty string for buffer name is not allowed"); @@ -656,7 +657,7 @@ delete_all_overlays (b) } /* Reinitialize everything about a buffer except its name and contents - and local variables. + and local variables. If called on an already-initialized buffer, the list of overlays should be deleted before calling this function, otherwise we end up with overlays that claim to belong to the buffer but the buffer @@ -770,7 +771,7 @@ DEFUN ("generate-new-buffer-name", Fgenerate_new_buffer_name, Sgenerate_new_buff doc: /* Return a string that is the name of no existing buffer based on NAME. If there is no live buffer named NAME, then return NAME. Otherwise modify name by appending `<NUMBER>', incrementing NUMBER -until an unused name is found, and then return that name. +\(starting at 2) until an unused name is found, and then return that name. Optional second argument IGNORE specifies a name that is okay to use \(if it is in the sequence to be tried) even if a buffer with that name exists. */) @@ -783,6 +784,9 @@ even if a buffer with that name exists. */) CHECK_STRING (name); + tem = Fstring_equal (name, ignore); + if (!NILP (tem)) + return name; tem = Fget_buffer (name); if (NILP (tem)) return name; @@ -1203,6 +1207,10 @@ If BUFFER is omitted or nil, some interesting buffer is returned. */) buf = Fcdr (XCAR (tail)); if (EQ (buf, buffer)) continue; + if (NILP (buf)) + continue; + if (NILP (XBUFFER (buf)->name)) + continue; if (SREF (XBUFFER (buf)->name, 0) == ' ') continue; /* If the selected frame has a buffer_predicate, @@ -1430,7 +1438,8 @@ with SIGHUP. */) if (STRINGP (b->auto_save_file_name) && b->auto_save_modified != 0 && BUF_SAVE_MODIFF (b) < b->auto_save_modified - && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b)) + && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b) + && NILP (Fsymbol_value (intern ("auto-save-visited-file-name")))) { Lisp_Object tem; tem = Fsymbol_value (intern ("delete-auto-save-files")); @@ -1674,8 +1683,9 @@ DEFUN ("pop-to-buffer", Fpop_to_buffer, Spop_to_buffer, 1, 3, 0, doc: /* Select buffer BUFFER in some window, preferably a different one. If BUFFER is nil, then some other buffer is chosen. If `pop-up-windows' is non-nil, windows can be split to do this. -If optional second arg OTHER-WINDOW is non-nil, insist on finding another -window even if BUFFER is already visible in the selected window. +If optional second arg OTHER-WINDOW is nil, insist on finding another +window even if BUFFER is already visible in the selected window, +and ignore `same-window-regexps' and `same-window-buffer-names'. This uses the function `display-buffer' as a subroutine; see the documentation of `display-buffer' for additional customization information. @@ -2082,7 +2092,9 @@ If FLAG is nil, this makes the buffer a single-byte buffer. In these cases, the buffer contents remain unchanged as a sequence of bytes but the contents viewed as characters do change. If FLAG is `to', this makes the buffer a multibyte buffer by changing -all eight-bit bytes to eight-bit characters. */) +all eight-bit bytes to eight-bit characters. +If the multibyte flag was really changed, undo information of the +current buffer is cleared. */) (flag) Lisp_Object flag; { @@ -3301,10 +3313,9 @@ adjust_overlays_for_delete (pos, length) endpoint in this range will need to be unlinked from the overlay list and reinserted in its proper place. Such an overlay might even have negative size at this point. - If so, we'll reverse the endpoints. Can you think of anything - better to do in this situation? */ + If so, we'll make the overlay empty. */ void -fix_overlays_in_range (start, end) +fix_start_end_in_overlays (start, end) register int start, end; { Lisp_Object overlay; @@ -3329,23 +3340,24 @@ fix_overlays_in_range (start, end) for (parent = NULL, tail = current_buffer->overlays_before; tail;) { XSETMISC (overlay, tail); + endpos = OVERLAY_POSITION (OVERLAY_END (overlay)); + startpos = OVERLAY_POSITION (OVERLAY_START (overlay)); + + /* If the overlay is backwards, make it empty. */ + if (endpos < startpos) + { + startpos = endpos; + Fset_marker (OVERLAY_START (overlay), make_number (startpos), + Qnil); + } + if (endpos < start) break; - startpos = OVERLAY_POSITION (OVERLAY_START (overlay)); + if (endpos < end || (startpos >= start && startpos < end)) { - /* If the overlay is backwards, fix that now. */ - if (startpos > endpos) - { - int tem; - Fset_marker (OVERLAY_START (overlay), make_number (endpos), - Qnil); - Fset_marker (OVERLAY_END (overlay), make_number (startpos), - Qnil); - tem = startpos; startpos = endpos; endpos = tem; - } /* Add it to the end of the wrong list. Later on, recenter_overlay_lists will move it to the right place. */ if (endpos < current_buffer->overlay_center) @@ -3376,22 +3388,24 @@ fix_overlays_in_range (start, end) for (parent = NULL, tail = current_buffer->overlays_after; tail;) { XSETMISC (overlay, tail); + startpos = OVERLAY_POSITION (OVERLAY_START (overlay)); + endpos = OVERLAY_POSITION (OVERLAY_END (overlay)); + + /* If the overlay is backwards, make it empty. */ + if (endpos < startpos) + { + startpos = endpos; + Fset_marker (OVERLAY_START (overlay), make_number (startpos), + Qnil); + } + if (startpos >= end) break; - endpos = OVERLAY_POSITION (OVERLAY_END (overlay)); + if (startpos >= start || (endpos >= start && endpos < end)) { - if (startpos > endpos) - { - int tem; - Fset_marker (OVERLAY_START (overlay), make_number (endpos), - Qnil); - Fset_marker (OVERLAY_END (overlay), make_number (startpos), - Qnil); - tem = startpos; startpos = endpos; endpos = tem; - } if (endpos < current_buffer->overlay_center) { if (!afterp) @@ -4974,6 +4988,7 @@ init_buffer_once () buffer_defaults.scroll_bar_width = Qnil; buffer_defaults.vertical_scroll_bar_type = Qt; buffer_defaults.indicate_empty_lines = Qnil; + buffer_defaults.indicate_buffer_boundaries = Qnil; buffer_defaults.scroll_up_aggressively = Qnil; buffer_defaults.scroll_down_aggressively = Qnil; buffer_defaults.display_time = Qnil; @@ -5043,6 +5058,7 @@ init_buffer_once () XSETFASTINT (buffer_local_flags.scroll_bar_width, idx); ++idx; XSETFASTINT (buffer_local_flags.vertical_scroll_bar_type, idx); ++idx; XSETFASTINT (buffer_local_flags.indicate_empty_lines, idx); ++idx; + XSETFASTINT (buffer_local_flags.indicate_buffer_boundaries, idx); ++idx; XSETFASTINT (buffer_local_flags.scroll_up_aggressively, idx); ++idx; XSETFASTINT (buffer_local_flags.scroll_down_aggressively, idx); ++idx; XSETFASTINT (buffer_local_flags.header_line_format, idx); ++idx; @@ -5331,6 +5347,11 @@ This is the same as (default-value 'vertical-scroll-bar). */); doc: /* Default value of `indicate-empty-lines' for buffers that don't override it. This is the same as (default-value 'indicate-empty-lines). */); + DEFVAR_LISP_NOPRO ("default-indicate-buffer-boundaries", + &buffer_defaults.indicate_buffer_boundaries, + doc: /* Default value of `indicate-buffer-boundaries' for buffers that don't override it. +This is the same as (default-value 'indicate-buffer-boundaries). */); + DEFVAR_LISP_NOPRO ("default-scroll-up-aggressively", &buffer_defaults.scroll_up_aggressively, doc: /* Default value of `scroll-up-aggressively'. @@ -5388,6 +5409,8 @@ A string is printed verbatim in the mode line except for %-constructs: %c -- print the current column number (this makes editing slower). To make the column number update correctly in all cases, `column-number-mode' must be non-nil. + %i -- print the size of the buffer. + %I -- like %i, but use k, M, G, etc., to abbreviate. %p -- print percent of buffer above top of window, or Top, Bot or All. %P -- print percent of buffer above bottom of window, perhaps plus Top, or print Bottom or All. @@ -5639,6 +5662,24 @@ A value of t means to use the vertical scroll bar type from the window's frame. If non-nil, a bitmap is displayed in the left fringe of a window on window-systems. */); + DEFVAR_PER_BUFFER ("indicate-buffer-boundaries", + ¤t_buffer->indicate_buffer_boundaries, Qnil, + doc: /* *Visually indicate buffer boundaries and scrolling. +If non-nil, the first and last line of the buffer are marked in the fringe +of a window on window-systems with angle bitmaps, or if the window can be +scrolled, the top and bottom line of the window are marked with up and down +arrow bitmaps. +If value is `left' or `right', both angle and arrow bitmaps are displayed in +the left or right fringe, resp. Any other non-nil value causes the +bitmap on the top line to be displayed in the left fringe, and the +bitmap on the bottom line in the right fringe. +If value is a cons (ANGLES . ARROWS), the car specifies the position +of the angle bitmaps, and the cdr specifies the position of the arrow +bitmaps. For example, (t . right) places the top angle bitmap in left +fringe, the bottom angle bitmap in right fringe, and both arrow +bitmaps in right fringe. To show just the angle bitmaps in the left +fringe, but no arrow bitmaps, use (left . nil). */); + DEFVAR_PER_BUFFER ("scroll-up-aggressively", ¤t_buffer->scroll_up_aggressively, Qnil, doc: /* How far to scroll windows upward. @@ -5907,3 +5948,6 @@ keys_of_buffer () initialized when that function gets called. */ Fput (intern ("erase-buffer"), Qdisabled, Qt); } + +/* arch-tag: e48569bf-69a9-4b65-a23b-8e68769436e1 + (do not change this comment) */ diff --git a/src/buffer.h b/src/buffer.h index b52f83a6e06..0755db25f9f 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -737,6 +737,9 @@ struct buffer like vi). */ Lisp_Object indicate_empty_lines; + /* Non-nil means indicate buffer boundaries and scrolling. */ + Lisp_Object indicate_buffer_boundaries; + /* Time stamp updated each time this buffer is displayed in a window. */ Lisp_Object display_time; @@ -911,8 +914,26 @@ extern int last_per_buffer_idx; (B)->local_flags[IDX] = (VAL); \ } while (0) -/* Return the index of the per-buffer variable at offset OFFSET in the - buffer structure. */ +/* Return the index value of the per-buffer variable at offset OFFSET + in the buffer structure. + + If the slot OFFSET has a corresponding default value in + buffer_defaults, the index value is positive and has only one + nonzero bit. When a buffer has its own local value for a slot, the + bit for that slot (found in the same slot in this structure) is + turned on in the buffer's local_flags array. + + If the index value is -1, even though there may be a + DEFVAR_PER_BUFFER for the slot, there is no default value for it; + and the corresponding slot in buffer_defaults is not used. + + If the index value is -2, then there is no DEFVAR_PER_BUFFER for + the slot, but there is a default value which is copied into each + new buffer. + + If a slot in this structure corresponding to a DEFVAR_PER_BUFFER is + zero, that is a bug */ + #define PER_BUFFER_IDX(OFFSET) \ XINT (*(Lisp_Object *)((OFFSET) + (char *) &buffer_local_flags)) @@ -940,3 +961,6 @@ extern int last_per_buffer_idx; #define PER_BUFFER_TYPE(OFFSET) \ (*(Lisp_Object *)((OFFSET) + (char *) &buffer_local_types)) + +/* arch-tag: 679305dd-d41c-4a50-b170-3caf5c97b2d1 + (do not change this comment) */ diff --git a/src/bytecode.c b/src/bytecode.c index f3a07dced35..659f79bca08 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -286,27 +286,13 @@ mark_byte_stack () The culprit is found in the frame of Fbyte_code where the address of its local variable `stack' is equal to the recorded value of `stack' here. */ - if (!stack->top) - abort (); + eassert (stack->top); for (obj = stack->bottom; obj <= stack->top; ++obj) - if (!XMARKBIT (*obj)) - { - mark_object (*obj); - XMARK (*obj); - } + mark_object (*obj); - if (!XMARKBIT (stack->byte_string)) - { - mark_object (stack->byte_string); - XMARK (stack->byte_string); - } - - if (!XMARKBIT (stack->constants)) - { - mark_object (stack->constants); - XMARK (stack->constants); - } + mark_object (stack->byte_string); + mark_object (stack->constants); } } @@ -318,16 +304,9 @@ void unmark_byte_stack () { struct byte_stack *stack; - Lisp_Object *obj; for (stack = byte_stack_list; stack; stack = stack->next) { - for (obj = stack->bottom; obj <= stack->top; ++obj) - XUNMARK (*obj); - - XUNMARK (stack->byte_string); - XUNMARK (stack->constants); - if (stack->byte_string_start != SDATA (stack->byte_string)) { int offset = stack->pc - stack->byte_string_start; @@ -1782,3 +1761,6 @@ integer, it is incremented each time that symbol's function is called. */); } #endif } + +/* arch-tag: b9803b6f-1ed6-4190-8adf-33fd3a9d10e9 + (do not change this comment) */ diff --git a/src/callint.c b/src/callint.c index 4edb4201fa4..50090db8b28 100644 --- a/src/callint.c +++ b/src/callint.c @@ -1,5 +1,5 @@ /* Call a Lisp function interactively. - Copyright (C) 1985, 86, 93, 94, 95, 1997, 2000, 02, 2003 + Copyright (C) 1985, 86, 93, 94, 95, 1997, 2000, 02, 03, 2004 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -41,6 +41,7 @@ Lisp_Object Qcall_interactively; Lisp_Object Vcommand_history; extern Lisp_Object Vhistory_length; +extern Lisp_Object Vthis_original_command, real_this_command; Lisp_Object Vcommand_debug_status, Qcommand_debug_status; Lisp_Object Qenable_recursive_minibuffers; @@ -208,7 +209,7 @@ fix_command (input, values) Lisp_Object intail, valtail; for (intail = Fcdr (input), valtail = values; CONSP (valtail); - intail = Fcdr (intail), valtail = Fcdr (valtail)) + intail = Fcdr (intail), valtail = XCDR (valtail)) { Lisp_Object elt; elt = Fcar (intail); @@ -291,6 +292,14 @@ supply if the command inquires which events were used to invoke it. */) int key_count; int record_then_fail = 0; + Lisp_Object save_this_command, save_last_command; + Lisp_Object save_this_original_command, save_real_this_command; + + save_this_command = Vthis_command; + save_this_original_command = Vthis_original_command; + save_real_this_command = real_this_command; + save_last_command = current_kboard->Vlast_command; + if (NILP (keys)) keys = this_command_keys, key_count = this_command_key_count; else @@ -338,25 +347,17 @@ supply if the command inquires which events were used to invoke it. */) goto lose; specs = XVECTOR (fun)->contents[COMPILED_INTERACTIVE]; } - else if (!CONSP (fun)) - goto lose; - else if (funcar = XCAR (fun), EQ (funcar, Qautoload)) + else { + Lisp_Object form; GCPRO2 (function, prefix_arg); - do_autoload (fun, function); + form = Finteractive_form (function); UNGCPRO; - goto retry; - } - else if (EQ (funcar, Qlambda)) - { - specs = Fassq (Qinteractive, Fcdr (XCDR (fun))); - if (NILP (specs)) + if (CONSP (form)) + specs = filter_specs = Fcar (XCDR (form)); + else goto lose; - filter_specs = Fnth (make_number (1), specs); - specs = Fcar (Fcdr (specs)); } - else - goto lose; /* If either SPECS or STRING is set to a string, use it. */ if (STRINGP (specs)) @@ -395,6 +396,12 @@ supply if the command inquires which events were used to invoke it. */) XSETCDR (teml, Qnil); } } + + Vthis_command = save_this_command; + Vthis_original_command = save_this_original_command; + real_this_command= save_real_this_command; + current_kboard->Vlast_command = save_last_command; + single_kboard_state (); return apply1 (function, specs); } @@ -841,6 +848,11 @@ supply if the command inquires which events were used to invoke it. */) if (record_then_fail) Fbarf_if_buffer_read_only (); + Vthis_command = save_this_command; + Vthis_original_command = save_this_original_command; + real_this_command= save_real_this_command; + current_kboard->Vlast_command = save_last_command; + single_kboard_state (); { @@ -978,3 +990,6 @@ a way to turn themselves off when a mouse command switches windows. */); defsubr (&Scall_interactively); defsubr (&Sprefix_numeric_value); } + +/* arch-tag: a3a7cad7-bcac-42ce-916e-1bd2546ebf37 + (do not change this comment) */ diff --git a/src/callproc.c b/src/callproc.c index 20b3ee22add..2b610d53a1d 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -123,6 +123,9 @@ int synch_process_alive; /* Nonzero => this is a string explaining death of synchronous subprocess. */ char *synch_process_death; +/* Nonzero => this is the signal number that terminated the subprocess. */ +int synch_process_termsig; + /* If synch_process_death is zero, this is exit code of synchronous subprocess. */ int synch_process_retcode; @@ -502,6 +505,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) to avoid timing error if process terminates soon. */ synch_process_death = 0; synch_process_retcode = 0; + synch_process_termsig = 0; if (NILP (error_file)) fd_error = emacs_open (NULL_DEVICE, O_WRONLY, 0); @@ -861,6 +865,19 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) unbind_to (count, Qnil); + if (synch_process_termsig) + { + char *signame; + + synchronize_system_messages_locale (); + signame = strsignal (synch_process_termsig); + + if (signame == 0) + signame = "unknown"; + + synch_process_death = signame; + } + if (synch_process_death) return code_convert_string_norecord (build_string (synch_process_death), Vlocale_coding_system, 0); @@ -1567,3 +1584,6 @@ See `setenv' and `getenv'. */); #endif defsubr (&Scall_process_region); } + +/* arch-tag: 769b8045-1df7-4d2b-8968-e3fb49017f95 + (do not change this comment) */ diff --git a/src/casefiddle.c b/src/casefiddle.c index 1e502af9c02..341e3b313a3 100644 --- a/src/casefiddle.c +++ b/src/casefiddle.c @@ -411,3 +411,6 @@ keys_of_casefiddle () initial_define_key (meta_map, 'l', "downcase-word"); initial_define_key (meta_map, 'c', "capitalize-word"); } + +/* arch-tag: 60a73c66-5489-47e7-a81f-cead4057c526 + (do not change this comment) */ diff --git a/src/casetab.c b/src/casetab.c index 9ee8f578a9b..af0b238029a 100644 --- a/src/casetab.c +++ b/src/casetab.c @@ -307,3 +307,6 @@ syms_of_casetab () defsubr (&Sset_case_table); defsubr (&Sset_standard_case_table); } + +/* arch-tag: e06388ad-99fe-40ec-ba67-9d010fcc4916 + (do not change this comment) */ diff --git a/src/ccl.c b/src/ccl.c index 528e7d5a435..5eac485bf2c 100644 --- a/src/ccl.c +++ b/src/ccl.c @@ -1697,7 +1697,7 @@ ccl_driver (ccl, source, destination, src_size, dst_size, charset_list) break; default: - sprintf(msg, "\nCCL: Unknown error type (%d).", ccl->status); + sprintf(msg, "\nCCL: Unknown error type (%d)", ccl->status); } msglen = strlen (msg); @@ -2290,3 +2290,6 @@ used by CCL. */); defsubr (&Sregister_ccl_program); defsubr (&Sregister_code_conversion_map); } + +/* arch-tag: bb9a37be-68ce-4576-8d3d-15d750e4a860 + (do not change this comment) */ diff --git a/src/ccl.h b/src/ccl.h index e1b8285df19..5f57f1f7711 100644 --- a/src/ccl.h +++ b/src/ccl.h @@ -112,3 +112,6 @@ EXFUN (Fccl_program_p, 1); } while (0); #endif /* EMACS_CCL_H */ + +/* arch-tag: 14681df7-876d-43de-bc71-6b78e23a4e3c + (do not change this comment) */ diff --git a/src/chartab.c b/src/chartab.c index c33ec0e7d06..71940761bfa 100644 --- a/src/chartab.c +++ b/src/chartab.c @@ -512,7 +512,7 @@ then the actual applicable value is inherited from the parent char-table DEFUN ("set-char-table-parent", Fset_char_table_parent, Sset_char_table_parent, 2, 2, 0, doc: /* Set the parent char-table of CHAR-TABLE to PARENT. -PARENT must be either nil or another char-table. */) +Return PARENT. PARENT must be either nil or another char-table. */) (char_table, parent) Lisp_Object char_table, parent; { @@ -597,10 +597,10 @@ a cons of character codes (for characters in the range), or a character code. * DEFUN ("set-char-table-range", Fset_char_table_range, Sset_char_table_range, 3, 3, 0, - doc: /* -Set the value in CHAR-TABLE for characters specified by RANGE to VALUE. + doc: /* Set the value in CHAR-TABLE for a range of characters RANGE to VALUE. RANGE should be t (for all characters), nil (for the default value), -a cons of character codes (for characters in the range), or a character code. */) +a cons of character codes (for characters in the range), +or a character code. Return VALUE. */) (char_table, range, value) Lisp_Object char_table, range, value; { diff --git a/src/chpdef.h b/src/chpdef.h index 43f7bbf4345..a1bdfb7ff82 100644 --- a/src/chpdef.h +++ b/src/chpdef.h @@ -36,3 +36,6 @@ #define CHP$V_READ 0 #define CHP$V_WRITE 1 #define CHP$V_USEREADALL 2 + +/* arch-tag: a7117984-e927-4f8e-932e-35d5fd524f12 + (do not change this comment) */ @@ -460,3 +460,6 @@ Wcm_init () return - 2; return 0; } + +/* arch-tag: bcf64c02-00f6-44ef-94b6-c56eab5b3dc4 + (do not change this comment) */ @@ -168,3 +168,6 @@ extern void cmcostinit (); extern void cmgoto (); extern void Wcm_clear (); extern int Wcm_init (); + +/* arch-tag: acc1535a-7136-49d6-b22d-9bc85702251b + (do not change this comment) */ diff --git a/src/cmds.c b/src/cmds.c index 2e63b2fbb52..1ac81af45a1 100644 --- a/src/cmds.c +++ b/src/cmds.c @@ -181,7 +181,7 @@ DEFUN ("end-of-line", Fend_of_line, Send_of_line, 0, 1, "p", doc: /* Move point to end of current line. With argument N not nil or 1, move forward N - 1 lines first. If point reaches the beginning or end of buffer, it stops there. -To ignore intangibility, bind `inhibit-text-motion-hooks' to t. +To ignore intangibility, bind `inhibit-point-motion-hooks' to t. This command does not move point across a field boundary unless doing so would move beyond there to a different line; if N is nil or 1, and @@ -627,3 +627,6 @@ keys_of_cmds () initial_define_key (global_map, Ctl ('F'), "forward-char"); initial_define_key (global_map, 0177, "delete-backward-char"); } + +/* arch-tag: 022ba3cd-67f9-4978-9c5d-7d2b18d8644e + (do not change this comment) */ diff --git a/src/commands.h b/src/commands.h index d830573b58b..f7831bc36a9 100644 --- a/src/commands.h +++ b/src/commands.h @@ -90,3 +90,6 @@ extern int update_mode_lines; so put cursor on minibuffer after the prompt. */ extern int cursor_in_echo_area; + +/* arch-tag: 4f7ca0b7-6a56-4b20-8bf5-b67a99921d1d + (do not change this comment) */ diff --git a/src/composite.h b/src/composite.h index d8c1fed4332..5d4dd024ce6 100644 --- a/src/composite.h +++ b/src/composite.h @@ -224,3 +224,6 @@ extern void compose_text P_ ((int, int, Lisp_Object, Lisp_Object, extern void compose_chars_in_text P_ ((int, int, Lisp_Object)); #endif /* not EMACS_COMPOSITE_H */ + +/* arch-tag: 59524d89-c645-47bd-b5e6-65e861690118 + (do not change this comment) */ diff --git a/src/config.in b/src/config.in index 5507ded42eb..0fb4b3f3444 100644 --- a/src/config.in +++ b/src/config.in @@ -163,6 +163,9 @@ Boston, MA 02111-1307, USA. */ /* Define to 1 if you have the `gai_strerror' function. */ #undef HAVE_GAI_STRERROR +/* Define to 1 if you have the `gdk_display_open' function. */ +#undef HAVE_GDK_DISPLAY_OPEN + /* Define to 1 if you have the `getaddrinfo' function. */ #undef HAVE_GETADDRINFO @@ -214,6 +217,9 @@ Boston, MA 02111-1307, USA. */ /* Define to 1 if using GTK. */ #undef HAVE_GTK +/* Define to 1 if GTK can handle more than one display. */ +#undef HAVE_GTK_MULTIDISPLAY + /* Define to 1 if netdb.h declares h_errno. */ #undef HAVE_H_ERRNO @@ -399,6 +405,9 @@ Boston, MA 02111-1307, USA. */ /* Define to 1 if you have the `mremap' function. */ #undef HAVE_MREMAP +/* Define to 1 if you have the <net/if.h> header file. */ +#undef HAVE_NET_IF_H + /* Define to 1 if you have the <nlist.h> header file. */ #undef HAVE_NLIST_H @@ -498,6 +507,21 @@ Boston, MA 02111-1307, USA. */ /* Define to 1 if you have the `strsignal' function. */ #undef HAVE_STRSIGNAL +/* Define to 1 if `ifr_addr' is member of `struct ifreq'. */ +#undef HAVE_STRUCT_IFREQ_IFR_ADDR + +/* Define to 1 if `ifr_broadaddr' is member of `struct ifreq'. */ +#undef HAVE_STRUCT_IFREQ_IFR_BROADADDR + +/* Define to 1 if `ifr_flags' is member of `struct ifreq'. */ +#undef HAVE_STRUCT_IFREQ_IFR_FLAGS + +/* Define to 1 if `ifr_hwaddr' is member of `struct ifreq'. */ +#undef HAVE_STRUCT_IFREQ_IFR_HWADDR + +/* Define to 1 if `ifr_netmask' is member of `struct ifreq'. */ +#undef HAVE_STRUCT_IFREQ_IFR_NETMASK + /* Define to 1 if `n_un.n_name' is member of `struct nlist'. */ #undef HAVE_STRUCT_NLIST_N_UN_N_NAME @@ -510,6 +534,9 @@ Boston, MA 02111-1307, USA. */ /* Define to 1 if you have the `sysinfo' function. */ #undef HAVE_SYSINFO +/* Define to 1 if you have the <sys/ioctl.h> header file. */ +#undef HAVE_SYS_IOCTL_H + /* Define to 1 if you have the <sys/mman.h> header file. */ #undef HAVE_SYS_MMAN_H @@ -522,6 +549,9 @@ Boston, MA 02111-1307, USA. */ /* Define to 1 if you have the <sys/select.h> header file. */ #undef HAVE_SYS_SELECT_H +/* Define to 1 if you have the <sys/socket.h> header file. */ +#undef HAVE_SYS_SOCKET_H + /* Define to 1 if you have the <sys/soundcard.h> header file. */ #undef HAVE_SYS_SOUNDCARD_H @@ -721,9 +751,9 @@ Boston, MA 02111-1307, USA. */ /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at run-time. - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown */ + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ #undef STACK_DIRECTION /* Define to 1 if you have the ANSI C header files. */ diff --git a/src/cxux-crt0.s b/src/cxux-crt0.s index cf973b1708f..615837eaeb4 100644 --- a/src/cxux-crt0.s +++ b/src/cxux-crt0.s @@ -36,3 +36,6 @@ __start: .data .globl _data_start _data_start: .space 4 + +/* arch-tag: ba84e4dc-615d-4a81-898c-f5b98ec71c9d + (do not change this comment) */ diff --git a/src/data.c b/src/data.c index 0e2a704f529..92e1c75dee4 100644 --- a/src/data.c +++ b/src/data.c @@ -1,5 +1,5 @@ /* Primitive operations on Lisp data types for GNU Emacs Lisp interpreter. - Copyright (C) 1985,86,88,93,94,95,97,98,99, 2000, 2001, 2003 + Copyright (C) 1985,86,88,93,94,95,97,98,99, 2000, 2001, 03, 2004 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -71,6 +71,7 @@ Lisp_Object Qinvalid_function, Qwrong_number_of_arguments, Qno_catch; Lisp_Object Qend_of_file, Qarith_error, Qmark_inactive; Lisp_Object Qbeginning_of_buffer, Qend_of_buffer, Qbuffer_read_only; Lisp_Object Qtext_read_only; + Lisp_Object Qintegerp, Qnatnump, Qwholenump, Qsymbolp, Qlistp, Qconsp; Lisp_Object Qstringp, Qarrayp, Qsequencep, Qbufferp; Lisp_Object Qchar_or_string_p, Qmarkerp, Qinteger_or_marker_p, Qvectorp; @@ -87,7 +88,8 @@ Lisp_Object Qoverflow_error, Qunderflow_error; Lisp_Object Qfloatp; Lisp_Object Qnumberp, Qnumber_or_marker_p; -static Lisp_Object Qinteger, Qsymbol, Qstring, Qcons, Qmarker, Qoverlay; +Lisp_Object Qinteger; +static Lisp_Object Qsymbol, Qstring, Qcons, Qmarker, Qoverlay; static Lisp_Object Qfloat, Qwindow_configuration, Qwindow; Lisp_Object Qprocess; static Lisp_Object Qcompiled_function, Qbuffer, Qframe, Qvector; @@ -728,7 +730,7 @@ determined by DEFINITION. */) } DEFUN ("setplist", Fsetplist, Ssetplist, 2, 2, 0, - doc: /* Set SYMBOL's property list to NEWVAL, and return NEWVAL. */) + doc: /* Set SYMBOL's property list to NEWPLIST, and return NEWPLIST. */) (symbol, newplist) register Lisp_Object symbol, newplist; { @@ -759,17 +761,39 @@ function with `&rest' args, or `unevalled' for a special form. */) return Fcons (make_number (minargs), make_number (maxargs)); } -DEFUN ("subr-interactive-form", Fsubr_interactive_form, Ssubr_interactive_form, 1, 1, 0, - doc: /* Return the interactive form of SUBR or nil if none. -SUBR must be a built-in function. Value, if non-nil, is a list +DEFUN ("interactive-form", Finteractive_form, Sinteractive_form, 1, 1, 0, + doc: /* Return the interactive form of CMD or nil if none. +CMD must be a command. Value, if non-nil, is a list \(interactive SPEC). */) - (subr) - Lisp_Object subr; + (cmd) + Lisp_Object cmd; { - if (!SUBRP (subr)) - wrong_type_argument (Qsubrp, subr); - if (XSUBR (subr)->prompt) - return list2 (Qinteractive, build_string (XSUBR (subr)->prompt)); + Lisp_Object fun = indirect_function (cmd); + + if (SUBRP (fun)) + { + if (XSUBR (fun)->prompt) + return list2 (Qinteractive, build_string (XSUBR (fun)->prompt)); + } + else if (COMPILEDP (fun)) + { + if ((ASIZE (fun) & PSEUDOVECTOR_SIZE_MASK) > COMPILED_INTERACTIVE) + return list2 (Qinteractive, AREF (fun, COMPILED_INTERACTIVE)); + } + else if (CONSP (fun)) + { + Lisp_Object funcar = XCAR (fun); + if (EQ (funcar, Qlambda)) + return Fassq (Qinteractive, Fcdr (XCDR (fun))); + else if (EQ (funcar, Qautoload)) + { + struct gcpro gcpro1; + GCPRO1 (cmd); + do_autoload (fun, cmd); + UNGCPRO; + return Finteractive_form (cmd); + } + } return Qnil; } @@ -871,6 +895,8 @@ store_symval_forwarding (symbol, valcontents, newval, buf) register Lisp_Object valcontents, newval; struct buffer *buf; { + int offset; + switch (SWITCH_ENUM_CAST (XTYPE (valcontents))) { case Lisp_Misc: @@ -890,6 +916,36 @@ store_symval_forwarding (symbol, valcontents, newval, buf) case Lisp_Misc_Objfwd: *XOBJFWD (valcontents)->objvar = newval; + + /* If this variable is a default for something stored + in the buffer itself, such as default-fill-column, + find the buffers that don't have local values for it + and update them. */ + if (XOBJFWD (valcontents)->objvar > (Lisp_Object *) &buffer_defaults + && XOBJFWD (valcontents)->objvar < (Lisp_Object *) (&buffer_defaults + 1)) + { + int offset = ((char *) XOBJFWD (valcontents)->objvar + - (char *) &buffer_defaults); + int idx = PER_BUFFER_IDX (offset); + + Lisp_Object tail, buf; + + if (idx <= 0) + break; + + for (tail = Vbuffer_alist; CONSP (tail); tail = XCDR (tail)) + { + Lisp_Object buf; + struct buffer *b; + + buf = Fcdr (XCAR (tail)); + if (!BUFFERP (buf)) continue; + b = XBUFFER (buf); + + if (! PER_BUFFER_VALUE_P (b, idx)) + PER_BUFFER_VALUE (b, offset) = newval; + } + } break; case Lisp_Misc_Buffer_Objfwd: @@ -1449,6 +1505,7 @@ The function `default-value' gets the default value and `set-default' sets it. register Lisp_Object tem, valcontents, newval; CHECK_SYMBOL (variable); + variable = indirect_variable (variable); valcontents = SYMBOL_VALUE (variable); if (EQ (variable, Qnil) || EQ (variable, Qt) || KBOARD_OBJFWDP (valcontents)) @@ -1502,6 +1559,7 @@ Instead, use `add-hook' and specify t for the LOCAL argument. */) register Lisp_Object tem, valcontents; CHECK_SYMBOL (variable); + variable = indirect_variable (variable); valcontents = SYMBOL_VALUE (variable); if (EQ (variable, Qnil) || EQ (variable, Qt) || KBOARD_OBJFWDP (valcontents)) @@ -1581,6 +1639,7 @@ From now on the default value will apply in this buffer. Return VARIABLE. */) register Lisp_Object tem, valcontents; CHECK_SYMBOL (variable); + variable = indirect_variable (variable); valcontents = SYMBOL_VALUE (variable); @@ -1645,6 +1704,7 @@ See `modify-frame-parameters' for how to set frame parameters. */) register Lisp_Object tem, valcontents, newval; CHECK_SYMBOL (variable); + variable = indirect_variable (variable); valcontents = SYMBOL_VALUE (variable); if (EQ (variable, Qnil) || EQ (variable, Qt) || KBOARD_OBJFWDP (valcontents) @@ -1694,6 +1754,7 @@ BUFFER defaults to the current buffer. */) } CHECK_SYMBOL (variable); + variable = indirect_variable (variable); valcontents = SYMBOL_VALUE (variable); if (BUFFER_LOCAL_VALUEP (valcontents) @@ -1701,7 +1762,6 @@ BUFFER defaults to the current buffer. */) { Lisp_Object tail, elt; - variable = indirect_variable (variable); for (tail = buf->local_var_alist; CONSP (tail); tail = XCDR (tail)) { elt = XCAR (tail); @@ -1738,6 +1798,7 @@ BUFFER defaults to the current buffer. */) } CHECK_SYMBOL (variable); + variable = indirect_variable (variable); valcontents = SYMBOL_VALUE (variable); @@ -1759,6 +1820,41 @@ BUFFER defaults to the current buffer. */) } return Qnil; } + +DEFUN ("variable-binding-locus", Fvariable_binding_locus, Svariable_binding_locus, + 1, 1, 0, + doc: /* Return a value indicating where VARIABLE's current binding comes from. +If the current binding is buffer-local, the value is the current buffer. +If the current binding is frame-local, the value is the selected frame. +If the current binding is global (the default), the value is nil. */) + (variable) + register Lisp_Object variable; +{ + Lisp_Object valcontents; + + CHECK_SYMBOL (variable); + variable = indirect_variable (variable); + + /* Make sure the current binding is actually swapped in. */ + find_symbol_value (variable); + + valcontents = XSYMBOL (variable)->value; + + if (BUFFER_LOCAL_VALUEP (valcontents) + || SOME_BUFFER_LOCAL_VALUEP (valcontents) + || BUFFER_OBJFWDP (valcontents)) + { + /* For a local variable, record both the symbol and which + buffer's or frame's value we are saving. */ + if (!NILP (Flocal_variable_p (variable, Qnil))) + return Fcurrent_buffer (); + else if (!BUFFER_OBJFWDP (valcontents) + && XBUFFER_LOCAL_VALUE (valcontents)->found_for_frame) + return XBUFFER_LOCAL_VALUE (valcontents)->frame; + } + + return Qnil; +} /* Find the function at the end of a chain of symbol function indirections. */ @@ -2701,6 +2797,20 @@ DEFUN ("lognot", Flognot, Slognot, 1, 1, 0, XSETINT (number, ~XINT (number)); return number; } + +DEFUN ("byteorder", Fbyteorder, Sbyteorder, 0, 0, 0, + doc: /* Return the byteorder for the machine. +Returns 66 (ASCII uppercase B) for big endian machines or 108 (ASCII +lowercase l) for small endian machines. */) + () +{ + unsigned i = 0x04030201; + int order = *(char *)&i == 1 ? 108 : 66; + + return make_number (order); +} + + void syms_of_data () @@ -3017,7 +3127,7 @@ syms_of_data () staticpro (&Qhash_table); defsubr (&Sindirect_variable); - defsubr (&Ssubr_interactive_form); + defsubr (&Sinteractive_form); defsubr (&Seq); defsubr (&Snull); defsubr (&Stype_of); @@ -3075,6 +3185,7 @@ syms_of_data () defsubr (&Smake_variable_frame_local); defsubr (&Slocal_variable_p); defsubr (&Slocal_variable_if_set_p); + defsubr (&Svariable_binding_locus); defsubr (&Saref); defsubr (&Saset); defsubr (&Snumber_to_string); @@ -3102,6 +3213,7 @@ syms_of_data () defsubr (&Sadd1); defsubr (&Ssub1); defsubr (&Slognot); + defsubr (&Sbyteorder); defsubr (&Ssubr_arity); XSYMBOL (Qwholenump)->function = XSYMBOL (Qnatnump)->function; @@ -3154,3 +3266,6 @@ init_data () signal (SIGEMT, arith_error); #endif /* uts */ } + +/* arch-tag: 25879798-b84d-479a-9c89-7d148e2109f7 + (do not change this comment) */ diff --git a/src/dired.c b/src/dired.c index bcb0be12f86..71597ebc9ea 100644 --- a/src/dired.c +++ b/src/dired.c @@ -1,5 +1,5 @@ /* Lisp functions for making directory listings. - Copyright (C) 1985, 1986, 1993, 1994, 1999, 2000, 2001 + Copyright (C) 1985, 1986, 1993, 1994, 1999, 2000, 2001, 2004 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -26,6 +26,13 @@ Boston, MA 02111-1307, USA. */ #include <sys/types.h> #include <sys/stat.h> +#ifdef VMS +#include "vms-pwd.h" +#else +#include <pwd.h> +#include <grp.h> +#endif + #include "systime.h" #include <errno.h> @@ -133,12 +140,14 @@ directory_files_internal_unwind (dh) /* Function shared by Fdirectory_files and Fdirectory_files_and_attributes. When ATTRS is zero, return a list of directory filenames; when - non-zero, return a list of directory filenames and their attributes. */ + non-zero, return a list of directory filenames and their attributes. + In the latter case, ID_FORMAT is passed to Ffile_attributes. */ Lisp_Object -directory_files_internal (directory, full, match, nosort, attrs) +directory_files_internal (directory, full, match, nosort, attrs, id_format) Lisp_Object directory, full, match, nosort; int attrs; + Lisp_Object id_format; { DIR *d; int directory_nbytes; @@ -296,7 +305,7 @@ directory_files_internal (directory, full, match, nosort, attrs) /* Both Fexpand_file_name and Ffile_attributes can GC. */ decoded_fullname = Fexpand_file_name (name, directory); - fileattrs = Ffile_attributes (decoded_fullname); + fileattrs = Ffile_attributes (decoded_fullname, id_format); list = Fcons (Fcons (finalname, fileattrs), list); UNGCPRO; @@ -351,32 +360,25 @@ If NOSORT is non-nil, the list is not sorted--its order is unpredictable. call the corresponding file handler. */ handler = Ffind_file_name_handler (directory, Qdirectory_files); if (!NILP (handler)) - { - Lisp_Object args[6]; - - args[0] = handler; - args[1] = Qdirectory_files; - args[2] = directory; - args[3] = full; - args[4] = match; - args[5] = nosort; - return Ffuncall (6, args); - } + return call5 (handler, Qdirectory_files, directory, + full, match, nosort); - return directory_files_internal (directory, full, match, nosort, 0); + return directory_files_internal (directory, full, match, nosort, 0, Qnil); } DEFUN ("directory-files-and-attributes", Fdirectory_files_and_attributes, - Sdirectory_files_and_attributes, 1, 4, 0, + Sdirectory_files_and_attributes, 1, 5, 0, doc: /* Return a list of names of files and their attributes in DIRECTORY. -There are three optional arguments: +There are four optional arguments: If FULL is non-nil, return absolute file names. Otherwise return names that are relative to the specified directory. If MATCH is non-nil, mention only file names that match the regexp MATCH. If NOSORT is non-nil, the list is not sorted--its order is unpredictable. - NOSORT is useful if you plan to sort the result yourself. */) - (directory, full, match, nosort) - Lisp_Object directory, full, match, nosort; + NOSORT is useful if you plan to sort the result yourself. +ID-FORMAT specifies the preferred format of attributes uid and gid, see +`file-attributes' for further documentation. */) + (directory, full, match, nosort, id_format) + Lisp_Object directory, full, match, nosort, id_format; { Lisp_Object handler; directory = Fexpand_file_name (directory, Qnil); @@ -385,19 +387,10 @@ If NOSORT is non-nil, the list is not sorted--its order is unpredictable. call the corresponding file handler. */ handler = Ffind_file_name_handler (directory, Qdirectory_files_and_attributes); if (!NILP (handler)) - { - Lisp_Object args[6]; - - args[0] = handler; - args[1] = Qdirectory_files_and_attributes; - args[2] = directory; - args[3] = full; - args[4] = match; - args[5] = nosort; - return Ffuncall (6, args); - } + return call6 (handler, Qdirectory_files_and_attributes, + directory, full, match, nosort, id_format); - return directory_files_internal (directory, full, match, nosort, 1); + return directory_files_internal (directory, full, match, nosort, 1, id_format); } @@ -873,14 +866,21 @@ make_time (time) Fcons (make_number (time & 0177777), Qnil)); } -DEFUN ("file-attributes", Ffile_attributes, Sfile_attributes, 1, 1, 0, +DEFUN ("file-attributes", Ffile_attributes, Sfile_attributes, 1, 2, 0, doc: /* Return a list of attributes of file FILENAME. Value is nil if specified file cannot be opened. -Otherwise, list elements are: + +ID-FORMAT specifies the preferred format of attributes uid and gid (see +below) - valid values are 'string and 'integer. The latter is the default, +but we plan to change that, so you should specify a non-nil value for +ID-FORMAT if you use the returned uid or gid. + +Elements of the attribute list are: 0. t for directory, string (name linked to) for symbolic link, or nil. 1. Number of links to file. - 2. File uid. - 3. File gid. + 2. File uid as a string or an integer. If a string value cannot be + looked up, the integer value is returned. + 3. File gid, likewise. 4. Last access time, as a list of two integers. First integer has high-order 16 bits of time, second has low 16 bits. 5. Last modification time, likewise. @@ -893,15 +893,15 @@ Otherwise, list elements are: this is a cons cell containing two integers: first the high part, then the low 16 bits. 11. Device number. If it is larger than the Emacs integer, this is - a cons cell, similar to the inode number. - -If file does not exist, returns nil. */) - (filename) - Lisp_Object filename; + a cons cell, similar to the inode number. */) + (filename, id_format) + Lisp_Object filename, id_format; { Lisp_Object values[12]; Lisp_Object encoded; struct stat s; + struct passwd *pw; + struct group *gr; #if defined (BSD4_2) || defined (BSD4_3) Lisp_Object dirname; struct stat sdir; @@ -915,7 +915,13 @@ If file does not exist, returns nil. */) call the corresponding file handler. */ handler = Ffind_file_name_handler (filename, Qfile_attributes); if (!NILP (handler)) - return call2 (handler, Qfile_attributes, filename); + { /* Only pass the extra arg if it is used to help backward compatibility + with old file handlers which do not implement the new arg. --Stef */ + if (NILP (id_format)) + return call2 (handler, Qfile_attributes, filename); + else + return call3 (handler, Qfile_attributes, filename, id_format); + } encoded = ENCODE_FILE (filename); @@ -934,8 +940,18 @@ If file does not exist, returns nil. */) #endif } values[1] = make_number (s.st_nlink); - values[2] = make_number (s.st_uid); - values[3] = make_number (s.st_gid); + if (NILP (id_format) || EQ (id_format, Qinteger)) + { + values[2] = make_number (s.st_uid); + values[3] = make_number (s.st_gid); + } + else + { + pw = (struct passwd *) getpwuid (s.st_uid); + values[2] = (pw ? build_string (pw->pw_name) : make_number (s.st_uid)); + gr = (struct group *) getgrgid (s.st_gid); + values[3] = (gr ? build_string (gr->gr_name) : make_number (s.st_gid)); + } values[4] = make_time (s.st_atime); values[5] = make_time (s.st_mtime); values[6] = make_time (s.st_ctime); @@ -1030,3 +1046,6 @@ This variable does not affect lists of possible completions, but does affect the commands that actually do completions. */); Vcompletion_ignored_extensions = Qnil; } + +/* arch-tag: 1ac8deca-4d8f-4d41-ade9-089154d98c03 + (do not change this comment) */ diff --git a/src/dispextern.h b/src/dispextern.h index 03eda50d714..f2cd03e968a 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -50,54 +50,30 @@ typedef struct { #ifdef HAVE_X_WINDOWS typedef struct x_display_info Display_Info; +typedef XImage * XImagePtr; +typedef XImagePtr XImagePtr_or_DC; #define NativeRectangle XRectangle #endif #ifdef HAVE_NTGUI #include "w32gui.h" typedef struct w32_display_info Display_Info; +typedef XImage *XImagePtr; +typedef HDC XImagePtr_or_DC; #endif #ifdef HAVE_CARBON #include "macgui.h" typedef struct mac_display_info Display_Info; - -/* Include Carbon.h to define Cursor and Rect. */ -#undef mktime -#undef DEBUG -#undef Z -#undef free -#undef malloc -#undef realloc -/* Macros max and min defined in lisp.h conflict with those in - precompiled header Carbon.h. */ -#undef max -#undef min -#undef init_process -#include <Carbon/Carbon.h> -#undef Z -#define Z (current_buffer->text->z) -#undef free -#define free unexec_free -#undef malloc -#define malloc unexec_malloc -#undef realloc -#define realloc unexec_realloc -#undef min -#define min(a, b) ((a) < (b) ? (a) : (b)) -#undef max -#define max(a, b) ((a) > (b) ? (a) : (b)) -#undef init_process -#define init_process emacs_init_process - +/* Mac equivalent of XImage. */ +typedef Pixmap XImagePtr; +typedef XImagePtr XImagePtr_or_DC; #endif - #ifndef NativeRectangle #define NativeRectangle int #endif - /* Structure forward declarations. Some are here because function prototypes below reference structure types before their definition in this file. Some are here because not every file including @@ -126,6 +102,9 @@ enum window_part ON_RIGHT_MARGIN }; +/* Number of bits allocated to store fringe bitmap numbers. */ +#define FRINGE_ID_BITS 8 + /*********************************************************************** @@ -321,6 +300,9 @@ struct glyph /* Width in pixels. */ short pixel_width; + /* Ascent and descent in pixels. */ + short ascent, descent; + /* Vertical offset. If < 0, the glyph is displayed raised, if > 0 the glyph is displayed lowered. */ short voffset; @@ -359,8 +341,10 @@ struct glyph doesn't have a glyph in a font. */ unsigned glyph_not_available_p : 1; +#define FACE_ID_BITS 21 + /* Face of the glyph. */ - unsigned face_id : 21; + unsigned face_id : FACE_ID_BITS; /* Type of font used to display the character glyph. May be used to determine which set of functions to use to obtain font metrics @@ -704,6 +688,33 @@ struct glyph_row position of the next row. */ struct display_pos end; + /* Left fringe bitmap number (enum fringe_bitmap_type). */ + unsigned left_user_fringe_bitmap : FRINGE_ID_BITS; + + /* Face of the left fringe glyph. */ + unsigned left_user_fringe_face_id : FACE_ID_BITS; + + /* Right fringe bitmap number (enum fringe_bitmap_type). */ + unsigned right_user_fringe_bitmap : FRINGE_ID_BITS; + + /* Face of the right fringe glyph. */ + unsigned right_user_fringe_face_id : FACE_ID_BITS; + + /* Left fringe bitmap number (enum fringe_bitmap_type). */ + unsigned left_fringe_bitmap : FRINGE_ID_BITS; + + /* Face of the left fringe glyph. */ + unsigned left_fringe_face_id : FACE_ID_BITS; + + /* Right fringe bitmap number (enum fringe_bitmap_type). */ + unsigned right_fringe_bitmap : FRINGE_ID_BITS; + + /* Face of the right fringe glyph. */ + unsigned right_fringe_face_id : FACE_ID_BITS; + + /* 1 means that we must draw the bitmaps of this row. */ + unsigned redraw_fringe_bitmaps_p : 1; + /* In a desired matrix, 1 means that this row must be updated. In a current matrix, 0 means that the row has been invalidated, i.e. the row's contents do not agree with what is visible on the @@ -772,6 +783,29 @@ struct glyph_row /* 1 means this row was ended by a newline from a string. */ unsigned ends_in_newline_from_string_p : 1; + /* 1 means this row width is exactly the width of the window, and the + final newline character is hidden in the right fringe. */ + unsigned exact_window_width_line_p : 1; + + /* 1 means this row currently shows the cursor in the right fringe. */ + unsigned cursor_in_fringe_p : 1; + + /* Non-zero means display a bitmap on X frames indicating that this + the first line of the buffer. */ + unsigned indicate_bob_p : 1; + + /* Non-zero means display a bitmap on X frames indicating that this + the top line of the window, but not start of the buffer. */ + unsigned indicate_top_line_p : 1; + + /* Non-zero means display a bitmap on X frames indicating that this + the last line of the buffer. */ + unsigned indicate_eob_p : 1; + + /* Non-zero means display a bitmap on X frames indicating that this + the bottom line of the window, but not end of the buffer. */ + unsigned indicate_bottom_line_p : 1; + /* Continuation lines width at the start of the row. */ int continuation_lines_width; }; @@ -1486,6 +1520,7 @@ enum face_id BASIC_FACE_ID_SENTINEL }; +#define MAX_FACE_ID ((1 << FACE_ID_BITS) - 1) /* A cache of realized faces. Each frame has its own cache because Emacs allows different frame-local face definitions. */ @@ -1564,26 +1599,6 @@ extern int face_change_count; Fringes ***********************************************************************/ -enum fringe_bitmap_type -{ - NO_FRINGE_BITMAP = 0, - LEFT_TRUNCATION_BITMAP, - RIGHT_TRUNCATION_BITMAP, - CONTINUED_LINE_BITMAP, - CONTINUATION_LINE_BITMAP, - OVERLAY_ARROW_BITMAP, - ZV_LINE_BITMAP, - MAX_FRINGE_BITMAPS -}; - -struct fringe_bitmap -{ - int width; - int height; - int period; - unsigned char *bits; -}; - /* Structure used to describe where and how to draw a fringe bitmap. WHICH is the fringe bitmap to draw. WD and H is the (adjusted) width and height of the bitmap, DH is the height adjustment (if @@ -1594,14 +1609,17 @@ struct fringe_bitmap struct draw_fringe_bitmap_params { - enum fringe_bitmap_type which; + int which; /* enum fringe_bitmap_type */ + unsigned short *bits; int wd, h, dh; int x, y; int bx, nx, by, ny; + unsigned cursor_p : 1; + unsigned overlay_p : 1; struct face *face; }; -extern struct fringe_bitmap fringe_bitmaps[MAX_FRINGE_BITMAPS]; +#define MAX_FRINGE_BITMAPS (1<<FRINGE_ID_BITS) /*********************************************************************** @@ -1772,6 +1790,10 @@ struct it thus we need at most 16 bytes here. */ Lisp_Object ctl_chars[16]; + /* Initial buffer or string position of the iterator, before skipping + over display properties and invisible text. */ + struct display_pos start; + /* Current buffer or string position of the iterator, including position in overlay strings etc. */ struct display_pos current; @@ -1958,6 +1980,9 @@ struct it glyph_row in move_it_to and display_line. */ int current_y; + /* Vertical matrix position of first text line in window. */ + int first_vpos; + /* Current vertical matrix position, or line number. Automatically incremented by move_it_to and display_line. */ int vpos; @@ -1965,6 +1990,18 @@ struct it /* Horizontal matrix position reached in move_it_in_display_line. Only set there, not in display_line. */ int hpos; + + /* Left fringe bitmap number (enum fringe_bitmap_type). */ + unsigned left_user_fringe_bitmap : FRINGE_ID_BITS; + + /* Face of the left fringe glyph. */ + unsigned left_user_fringe_face_id : FACE_ID_BITS; + + /* Right fringe bitmap number (enum fringe_bitmap_type). */ + unsigned right_user_fringe_bitmap : FRINGE_ID_BITS; + + /* Face of the right fringe glyph. */ + unsigned right_user_fringe_face_id : FACE_ID_BITS; }; @@ -2121,6 +2158,11 @@ struct redisplay_interface void (*draw_fringe_bitmap) P_ ((struct window *w, struct glyph_row *row, struct draw_fringe_bitmap_params *p)); + /* Define and destroy fringe bitmap no. WHICH. */ + void (*define_fringe_bitmap) P_ ((int which, unsigned short *bits, + int h, int wd)); + void (*destroy_fringe_bitmap) P_ ((int which)); + /* Get metrics of character CHAR2B in FONT of type FONT_TYPE. Value is null if CHAR2B is not contained in the font. */ XCharStruct * (*per_char_metric) P_ ((XFontStruct *font, XChar2b *char2b, @@ -2443,7 +2485,9 @@ int window_box_height P_ ((struct window *)); int window_text_bottom_y P_ ((struct window *)); int window_box_width P_ ((struct window *, int)); int window_box_left P_ ((struct window *, int)); +int window_box_left_offset P_ ((struct window *, int)); int window_box_right P_ ((struct window *, int)); +int window_box_right_offset P_ ((struct window *, int)); void window_box_edges P_ ((struct window *, int, int *, int *, int *, int *)); int estimate_mode_line_height P_ ((struct frame *, enum face_id)); void pixel_to_glyph_coords P_ ((struct frame *, int, int, int *, int *, @@ -2470,8 +2514,6 @@ void move_it_past_eol P_ ((struct it *)); int in_display_vector_p P_ ((struct it *)); int frame_mode_line_height P_ ((struct frame *)); void highlight_trailing_whitespace P_ ((struct frame *, struct glyph_row *)); -void draw_row_fringe_bitmaps P_ ((struct window *, struct glyph_row *)); -void compute_fringe_widths P_ ((struct frame *, int)); extern Lisp_Object Qtool_bar; extern Lisp_Object Vshow_trailing_whitespace; extern int mode_line_in_non_selected_windows; @@ -2487,6 +2529,9 @@ extern struct frame *last_mouse_frame; extern int last_tool_bar_item; extern int mouse_autoselect_window; +extern int calc_pixel_width_or_height P_ ((double *, struct it *, Lisp_Object, + /* XFontStruct */ void *, int, int *)); + #ifdef HAVE_WINDOW_SYSTEM #if GLYPH_DEBUG @@ -2523,6 +2568,7 @@ extern void x_draw_vertical_border P_ ((struct window *w)); extern void frame_to_window_pixel_xy P_ ((struct window *, int *, int *)); extern void get_glyph_string_clip_rect P_ ((struct glyph_string *, NativeRectangle *nr)); +extern Lisp_Object find_hot_spot P_ ((Lisp_Object, int, int)); extern void note_mouse_highlight P_ ((struct frame *, int, int)); extern void x_clear_window_mouse_face P_ ((struct window *)); extern void cancel_mouse_face P_ ((struct frame *)); @@ -2540,6 +2586,55 @@ extern int x_intersect_rectangles P_ ((XRectangle *, XRectangle *, XRectangle *)); #endif +/* Defined in fringe.c */ + +int valid_fringe_bitmap_id_p (int); +void draw_fringe_bitmap P_ ((struct window *, struct glyph_row *, int)); +void draw_row_fringe_bitmaps P_ ((struct window *, struct glyph_row *)); +void draw_window_fringes P_ ((struct window *)); +int update_window_fringes P_ ((struct window *, int)); +void compute_fringe_widths P_ ((struct frame *, int)); + +#ifdef WINDOWS_NT +void w32_init_fringe P_ ((void)); +void w32_reset_fringes P_ ((void)); +#endif + +/* Defined in image.c */ + +#ifdef HAVE_WINDOW_SYSTEM + +extern int x_bitmap_height P_ ((struct frame *, int)); +extern int x_bitmap_width P_ ((struct frame *, int)); +extern int x_bitmap_pixmap P_ ((struct frame *, int)); +extern void x_reference_bitmap P_ ((struct frame *, int)); +extern int x_create_bitmap_from_data P_ ((struct frame *, char *, + unsigned int, unsigned int)); +extern int x_create_bitmap_from_file P_ ((struct frame *, Lisp_Object)); +#ifndef x_destroy_bitmap +extern void x_destroy_bitmap P_ ((struct frame *, int)); +#endif +extern void x_destroy_all_bitmaps P_ ((Display_Info *)); +extern int x_create_bitmap_mask P_ ((struct frame * , int)); +extern Lisp_Object x_find_image_file P_ ((Lisp_Object)); + +void x_kill_gs_process P_ ((Pixmap, struct frame *)); +struct image_cache *make_image_cache P_ ((void)); +void free_image_cache P_ ((struct frame *)); +void clear_image_cache P_ ((struct frame *, int)); +void forall_images_in_image_cache P_ ((struct frame *, + void (*) P_ ((struct image *)))); +int valid_image_p P_ ((Lisp_Object)); +void prepare_image_for_display P_ ((struct frame *, struct image *)); +int lookup_image P_ ((struct frame *, Lisp_Object)); + +unsigned long image_background P_ ((struct image *, struct frame *, + XImagePtr_or_DC ximg)); +int image_background_transparent P_ ((struct image *, struct frame *, + XImagePtr_or_DC mask)); + +#endif + /* Defined in sysdep.c */ void get_frame_size P_ ((int *, int *)); @@ -2596,27 +2691,14 @@ void gamma_correct P_ ((struct frame *, XColor *)); #ifdef WINDOWSNT void gamma_correct P_ ((struct frame *, COLORREF *)); #endif +#ifdef MAC_OS +void gamma_correct P_ ((struct frame *, unsigned long *)); +#endif #ifdef HAVE_WINDOW_SYSTEM -void x_kill_gs_process P_ ((Pixmap, struct frame *)); int x_screen_planes P_ ((struct frame *)); void x_implicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object)); -struct image_cache *make_image_cache P_ ((void)); -void free_image_cache P_ ((struct frame *)); -void clear_image_cache P_ ((struct frame *, int)); -void forall_images_in_image_cache P_ ((struct frame *, - void (*) P_ ((struct image *)))); -int valid_image_p P_ ((Lisp_Object)); -void prepare_image_for_display P_ ((struct frame *, struct image *)); -int lookup_image P_ ((struct frame *, Lisp_Object)); - -#ifdef HAVE_X_WINDOWS -unsigned long image_background P_ ((struct image *, struct frame *, - XImage *ximg)); -int image_background_transparent P_ ((struct image *, struct frame *, - XImage *mask)); -#endif /* HAVE_X_WINDOWS */ extern Lisp_Object tip_frame; extern Window tip_window; @@ -2656,10 +2738,19 @@ int popup_activated P_ ((void)); extern int inverse_video; extern int required_matrix_width P_ ((struct window *)); extern int required_matrix_height P_ ((struct window *)); -extern Lisp_Object mode_line_string P_ ((struct window *, int, int, - enum window_part, int *)); -extern Lisp_Object marginal_area_string P_ ((struct window *, int, int, - enum window_part, int *)); +extern Lisp_Object buffer_posn_from_coords P_ ((struct window *, + int *, int *, + struct display_pos *, + Lisp_Object *, + int *, int *, int *, int *)); +extern Lisp_Object mode_line_string P_ ((struct window *, enum window_part, + int *, int *, int *, + Lisp_Object *, + int *, int *, int *, int *)); +extern Lisp_Object marginal_area_string P_ ((struct window *, enum window_part, + int *, int *, int *, + Lisp_Object *, + int *, int *, int *, int *)); extern void redraw_frame P_ ((struct frame *)); extern void redraw_garbaged_frames P_ ((void)); extern void cancel_line P_ ((int, struct frame *)); @@ -2700,8 +2791,6 @@ int direct_output_forward_char P_ ((int)); int update_frame P_ ((struct frame *, int, int)); void update_single_window P_ ((struct window *, int)); int scrolling P_ ((struct frame *)); -void buffer_posn_from_coords P_ ((struct window *, int *, int *, - Lisp_Object *, struct display_pos *)); void do_pending_window_change P_ ((int)); void change_frame_size P_ ((struct frame *, int, int, int, int, int)); void bitch_at_user P_ ((void)); @@ -2779,3 +2868,6 @@ extern Lisp_Object x_default_parameter P_ ((struct frame *, Lisp_Object, #endif /* HAVE_WINDOW_SYSTEM */ #endif /* not DISPEXTERN_H_INCLUDED */ + +/* arch-tag: c65c475f-1c1e-4534-8795-990b8509fd65 + (do not change this comment) */ diff --git a/src/dispnew.c b/src/dispnew.c index 63435c54d82..f06a54164d6 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -1,5 +1,5 @@ /* Updating of data structures for redisplay. - Copyright (C) 1985,86,87,88,93,94,95,97,98,1999,2000,01,02,2003 + Copyright (C) 1985,86,87,88,93,94,95,97,98,1999,2000,01,02,03,04 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -625,20 +625,23 @@ adjust_glyph_matrix (w, matrix, x, y, dim) int left = -1, right = -1; int window_width = -1, window_height; - /* See if W had a header line that has disappeared now, or vice versa. */ + /* See if W had a header line that has disappeared now, or vice versa. + Get W's size. */ if (w) { + window_box (w, -1, 0, 0, &window_width, &window_height); + header_line_p = WINDOW_WANTS_HEADER_LINE_P (w); header_line_changed_p = header_line_p != matrix->header_line_p; } matrix->header_line_p = header_line_p; - /* Do nothing if MATRIX' size, position, vscroll, and marginal areas + /* If POOL is null, MATRIX is a window matrix for window-based redisplay. + Do nothing if MATRIX' size, position, vscroll, and marginal areas haven't changed. This optimization is important because preserving the matrix means preventing redisplay. */ if (matrix->pool == NULL) { - window_box (w, -1, 0, 0, &window_width, &window_height); left = margin_glyphs_to_reserve (w, dim.width, w->left_margin_cols); right = margin_glyphs_to_reserve (w, dim.width, w->right_margin_cols); xassert (left >= 0 && right >= 0); @@ -723,7 +726,8 @@ adjust_glyph_matrix (w, matrix, x, y, dim) else { /* If MATRIX->pool is null, MATRIX is responsible for managing - its own memory. Allocate glyph memory from the heap. */ + its own memory. It is a window matrix for window-based redisplay. + Allocate glyph memory from the heap. */ if (dim.width > matrix->matrix_w || new_rows || header_line_changed_p @@ -1509,12 +1513,14 @@ row_equal_p (w, a, b, mouse_face_p) return 0; } - if (a->truncated_on_left_p != b->truncated_on_left_p - || a->fill_line_p != b->fill_line_p - || a->truncated_on_right_p != b->truncated_on_right_p + if (a->fill_line_p != b->fill_line_p + || a->cursor_in_fringe_p != b->cursor_in_fringe_p + || a->left_fringe_bitmap != b->left_fringe_bitmap + || a->left_fringe_face_id != b->left_fringe_face_id + || a->right_fringe_bitmap != b->right_fringe_bitmap + || a->right_fringe_face_id != b->right_fringe_face_id || a->overlay_arrow_p != b->overlay_arrow_p - || a->continued_p != b->continued_p - || a->indicate_empty_line_p != b->indicate_empty_line_p + || a->exact_window_width_line_p != b->exact_window_width_line_p || a->overlapped_p != b->overlapped_p || (MATRIX_ROW_CONTINUATION_LINE_P (a) != MATRIX_ROW_CONTINUATION_LINE_P (b)) @@ -3432,6 +3438,7 @@ direct_output_for_insert (g) /* Can't do it in a continued line because continuation lines would change. */ (glyph_row->continued_p + || glyph_row->exact_window_width_line_p /* Can't use this method if the line overlaps others or is overlapped by others because these other lines would have to be redisplayed. */ @@ -3637,6 +3644,10 @@ direct_output_for_insert (g) cursor_to (y, x); } +#ifdef HAVE_WINDOW_SYSTEM + update_window_fringes (w, 0); +#endif + if (rif) rif->update_window_end_hook (w, 1, 0); update_end (f); @@ -3804,10 +3815,15 @@ update_frame (f, force_p, inhibit_hairy_id_p) paused_p = update_window_tree (root_window, force_p); update_end (f); -#if 0 /* This flush is a performance bottleneck under X, - and it doesn't seem to be necessary anyway. */ - rif->flush_display (f); -#endif + /* This flush is a performance bottleneck under X, + and it doesn't seem to be necessary anyway (in general). + It is necessary when resizing the window with the mouse, or + at least the fringes are not redrawn in a timely manner. ++kfs */ + if (f->force_flush_display_p) + { + rif->flush_display (f); + f->force_flush_display_p = 0; + } } else { @@ -4100,19 +4116,11 @@ update_window (w, force_p) goto set_cursor; } else if (rc > 0) - /* We've scrolled the display. */ - force_p = 1; - changed_p = 1; - } - - /* Update the header line after scrolling because a new header - line would otherwise overwrite lines at the top of the window - that can be scrolled. */ - if (header_line_row && header_line_row->enabled_p) - { - header_line_row->y = 0; - update_window_line (w, 0, &mouse_face_overwritten_p); - changed_p = 1; + { + /* We've scrolled the display. */ + force_p = 1; + changed_p = 1; + } } /* Update the rest of the lines. */ @@ -4151,6 +4159,16 @@ update_window (w, force_p) set_cursor: + /* Update the header line after scrolling because a new header + line would otherwise overwrite lines at the top of the window + that can be scrolled. */ + if (header_line_row && header_line_row->enabled_p) + { + header_line_row->y = 0; + update_window_line (w, 0, &mouse_face_overwritten_p); + changed_p = 1; + } + /* Fix the appearance of overlapping/overlapped rows. */ if (!paused_p && !w->pseudo_window_p) { @@ -4174,6 +4192,10 @@ update_window (w, force_p) strcpy (w->current_matrix->method, w->desired_matrix->method); #endif +#ifdef HAVE_WINDOW_SYSTEM + update_window_fringes (w, 0); +#endif + /* End the update of window W. Don't set the cursor if we paused updating the display because in this case, set_window_cursor_after_update hasn't been called, and @@ -4403,7 +4425,7 @@ update_text_area (w, vpos) /* If old row extends to the end of the text area, clear. */ if (i >= desired_row->used[TEXT_AREA]) rif->cursor_to (vpos, i, desired_row->y, - desired_row->x + desired_row->pixel_width); + desired_row->pixel_width); rif->clear_end_of_line (-1); changed_p = 1; } @@ -4415,7 +4437,7 @@ update_text_area (w, vpos) if (i >= desired_row->used[TEXT_AREA]) rif->cursor_to (vpos, i, desired_row->y, - desired_row->x + desired_row->pixel_width); + desired_row->pixel_width); /* If cursor is displayed at the end of the line, make sure it's cleared. Nowadays we don't have a phys_cursor_glyph @@ -4429,7 +4451,7 @@ update_text_area (w, vpos) x = -1; } else - x = current_row->x + current_row->pixel_width; + x = current_row->pixel_width; rif->clear_end_of_line (x); changed_p = 1; } @@ -4492,13 +4514,11 @@ update_window_line (w, vpos, mouse_face_overwritten_p) if (!current_row->enabled_p || desired_row->y != current_row->y || desired_row->visible_height != current_row->visible_height + || desired_row->cursor_in_fringe_p != current_row->cursor_in_fringe_p || desired_row->overlay_arrow_p != current_row->overlay_arrow_p - || desired_row->truncated_on_left_p != current_row->truncated_on_left_p - || desired_row->truncated_on_right_p != current_row->truncated_on_right_p - || desired_row->continued_p != current_row->continued_p + || current_row->redraw_fringe_bitmaps_p || desired_row->mode_line_p != current_row->mode_line_p - || (desired_row->indicate_empty_line_p - != current_row->indicate_empty_line_p) + || desired_row->exact_window_width_line_p != current_row->exact_window_width_line_p || (MATRIX_ROW_CONTINUATION_LINE_P (desired_row) != MATRIX_ROW_CONTINUATION_LINE_P (current_row))) rif->after_update_window_line_hook (desired_row); @@ -4751,6 +4771,7 @@ scrolling_window (w, header_line_p) if (c->enabled_p && d->enabled_p + && !d->redraw_fringe_bitmaps_p && c->y == d->y && MATRIX_ROW_BOTTOM_Y (c) <= yb && MATRIX_ROW_BOTTOM_Y (d) <= yb @@ -4806,6 +4827,7 @@ scrolling_window (w, header_line_p) && MATRIX_ROW (current_matrix, i - 1)->enabled_p && (MATRIX_ROW (current_matrix, i - 1)->y == MATRIX_ROW (desired_matrix, j - 1)->y) + && !MATRIX_ROW (desired_matrix, j - 1)->redraw_fringe_bitmaps_p && row_equal_p (w, MATRIX_ROW (desired_matrix, i - 1), MATRIX_ROW (current_matrix, j - 1), 1)) @@ -4998,6 +5020,13 @@ scrolling_window (w, header_line_p) to = MATRIX_ROW (current_matrix, r->desired_vpos + j); from = MATRIX_ROW (desired_matrix, r->desired_vpos + j); to_overlapped_p = to->overlapped_p; + if (!from->mode_line_p && !w->pseudo_window_p + && (to->left_fringe_bitmap != from->left_fringe_bitmap + || to->right_fringe_bitmap != from->right_fringe_bitmap + || to->left_fringe_face_id != from->left_fringe_face_id + || to->right_fringe_face_id != from->right_fringe_face_id + || to->overlay_arrow_p != from->overlay_arrow_p)) + from->redraw_fringe_bitmaps_p = 1; assign_row (to, from); to->enabled_p = 1, from->enabled_p = 0; to->overlapped_p = to_overlapped_p; @@ -5008,8 +5037,8 @@ scrolling_window (w, header_line_p) for (i = 0; i < row_entry_idx; ++i) row_table[row_entry_pool[i].bucket] = NULL; - /* Value is non-zero to indicate that we scrolled the display. */ - return 1; + /* Value is > 0 to indicate that we scrolled the display. */ + return nruns; } @@ -5669,21 +5698,25 @@ update_frame_line (f, vpos) ***********************************************************************/ /* Determine what's under window-relative pixel position (*X, *Y). - Return in *OBJECT the object (string or buffer) that's there. - Return in *POS the position in that object. Adjust *X and *Y - to character boundaries. */ + Return the object (string or buffer) that's there. + Return in *POS the position in that object. + Adjust *X and *Y to character positions. */ -void -buffer_posn_from_coords (w, x, y, object, pos) +Lisp_Object +buffer_posn_from_coords (w, x, y, pos, object, dx, dy, width, height) struct window *w; int *x, *y; - Lisp_Object *object; struct display_pos *pos; + Lisp_Object *object; + int *dx, *dy; + int *width, *height; { struct it it; struct buffer *old_current_buffer = current_buffer; struct text_pos startp; - int left_area_width; + Lisp_Object string; + struct glyph_row *row; + int x0, x1; current_buffer = XBUFFER (w->buffer); SET_TEXT_POS_FROM_MARKER (startp, w->start); @@ -5691,40 +5724,91 @@ buffer_posn_from_coords (w, x, y, object, pos) BYTEPOS (startp) = min (ZV_BYTE, max (BEGV_BYTE, BYTEPOS (startp))); start_display (&it, w, startp); - left_area_width = WINDOW_LEFT_MARGIN_WIDTH (w); - move_it_to (&it, -1, *x + it.first_visible_x - left_area_width, *y, -1, + x0 = *x - WINDOW_LEFT_MARGIN_WIDTH (w); + move_it_to (&it, -1, x0 + it.first_visible_x, *y, -1, MOVE_TO_X | MOVE_TO_Y); - *x = it.current_x - it.first_visible_x + left_area_width; - *y = it.current_y; current_buffer = old_current_buffer; - *object = STRINGP (it.string) ? it.string : w->buffer; + *dx = x0 + it.first_visible_x - it.current_x; + *dy = *y - it.current_y; + + string = w->buffer; + if (STRINGP (it.string)) + string = it.string; *pos = it.current; + +#ifdef HAVE_WINDOW_SYSTEM + if (it.what == IT_IMAGE) + { + struct image *img; + if ((img = IMAGE_FROM_ID (it.f, it.image_id)) != NULL + && !NILP (img->spec)) + *object = img->spec; + } +#endif + + row = MATRIX_ROW (w->current_matrix, it.vpos); + if (row->enabled_p) + { + if (it.hpos < row->used[TEXT_AREA]) + { + struct glyph *glyph = row->glyphs[TEXT_AREA] + it.hpos; + *width = glyph->pixel_width; + *height = glyph->ascent + glyph->descent; +#ifdef HAVE_WINDOW_SYSTEM + if (glyph->type == IMAGE_GLYPH) + *dy -= row->ascent - glyph->ascent; +#endif + } + else + { + *width = 0; + *height = row->height; + } + } + else + { + *width = *height = 0; + } + + /* Add extra (default width) columns if clicked after EOL. */ + x1 = max(0, it.current_x + it.pixel_width - it.first_visible_x); + if (x0 > x1) + it.hpos += (x0 - x1) / WINDOW_FRAME_COLUMN_WIDTH (w); + + *x = it.hpos; + *y = it.vpos; + + return string; } /* Value is the string under window-relative coordinates X/Y in the - mode or header line of window W, or nil if none. MODE_LINE_P non-zero - means look at the mode line. *CHARPOS is set to the position in - the string returned. */ + mode line or header line (PART says which) of window W, or nil if none. + *CHARPOS is set to the position in the string returned. */ Lisp_Object -mode_line_string (w, x, y, part, charpos) +mode_line_string (w, part, x, y, charpos, object, dx, dy, width, height) struct window *w; - int x, y; enum window_part part; + int *x, *y; int *charpos; + Lisp_Object *object; + int *dx, *dy; + int *width, *height; { struct glyph_row *row; struct glyph *glyph, *end; - int x0; + int x0, y0; Lisp_Object string = Qnil; if (part == ON_MODE_LINE) row = MATRIX_MODE_LINE_ROW (w->current_matrix); else row = MATRIX_HEADER_LINE_ROW (w->current_matrix); + y0 = *y - row->y; + *y = row - MATRIX_FIRST_TEXT_ROW (w->current_matrix); if (row->mode_line_p && row->enabled_p) { @@ -5732,15 +5816,44 @@ mode_line_string (w, x, y, part, charpos) it's the one we were looking for. */ glyph = row->glyphs[TEXT_AREA]; end = glyph + row->used[TEXT_AREA]; - for (x0 = 0; glyph < end; x0 += glyph->pixel_width, ++glyph) - if (x >= x0 && x < x0 + glyph->pixel_width) - { - string = glyph->object; - *charpos = glyph->charpos; - break; - } + for (x0 = *x; glyph < end && x0 > glyph->pixel_width; ++glyph) + x0 -= glyph->pixel_width; + *x = glyph - row->glyphs[TEXT_AREA]; + if (glyph < end) + { + string = glyph->object; + *charpos = glyph->charpos; + *width = glyph->pixel_width; + *height = glyph->ascent + glyph->descent; +#ifdef HAVE_WINDOW_SYSTEM + if (glyph->type == IMAGE_GLYPH) + { + struct image *img; + img = IMAGE_FROM_ID (WINDOW_XFRAME (w), glyph->u.img_id); + if (img != NULL) + *object = img->spec; + y0 -= row->ascent - glyph->ascent; + } +#endif + } + else + { + /* Add extra (default width) columns if clicked after EOL. */ + *x += x0 / WINDOW_FRAME_COLUMN_WIDTH (w); + *width = 0; + *height = row->height; + } + } + else + { + *x = 0; + x0 = 0; + *width = *height = 0; } + *dx = x0; + *dy = y0; + return string; } @@ -5750,15 +5863,18 @@ mode_line_string (w, x, y, part, charpos) the string returned. */ Lisp_Object -marginal_area_string (w, x, y, part, charpos) +marginal_area_string (w, part, x, y, charpos, object, dx, dy, width, height) struct window *w; - int x, y; enum window_part part; + int *x, *y; int *charpos; + Lisp_Object *object; + int *dx, *dy; + int *width, *height; { struct glyph_row *row = w->current_matrix->rows; struct glyph *glyph, *end; - int x0, i, wy = y; + int x0, y0, i, wy = *y; int area; Lisp_Object string = Qnil; @@ -5772,33 +5888,63 @@ marginal_area_string (w, x, y, part, charpos) for (i = 0; row->enabled_p && i < w->current_matrix->nrows; ++i, ++row) if (wy >= row->y && wy < MATRIX_ROW_BOTTOM_Y (row)) break; + y0 = *y - row->y; + *y = row - MATRIX_FIRST_TEXT_ROW (w->current_matrix); if (row->enabled_p) { /* Find the glyph under X. If we find one with a string object, it's the one we were looking for. */ - glyph = row->glyphs[area]; - end = glyph + row->used[area]; - if (area == RIGHT_MARGIN_AREA) x0 = ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) - ? WINDOW_LEFT_FRINGE_WIDTH (w) + ? WINDOW_LEFT_FRINGE_WIDTH (w) : WINDOW_TOTAL_FRINGE_WIDTH (w)) + window_box_width (w, LEFT_MARGIN_AREA) + window_box_width (w, TEXT_AREA)); else x0 = (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) - ? WINDOW_LEFT_FRINGE_WIDTH (w) + ? WINDOW_LEFT_FRINGE_WIDTH (w) : 0); - for (; glyph < end; x0 += glyph->pixel_width, ++glyph) - if (x >= x0 && x < x0 + glyph->pixel_width) - { - string = glyph->object; - *charpos = glyph->charpos; - break; - } + glyph = row->glyphs[area]; + end = glyph + row->used[area]; + for (x0 = *x - x0; glyph < end && x0 > glyph->pixel_width; ++glyph) + x0 -= glyph->pixel_width; + *x = glyph - row->glyphs[area]; + if (glyph < end) + { + string = glyph->object; + *charpos = glyph->charpos; + *width = glyph->pixel_width; + *height = glyph->ascent + glyph->descent; +#ifdef HAVE_WINDOW_SYSTEM + if (glyph->type == IMAGE_GLYPH) + { + struct image *img; + img = IMAGE_FROM_ID (WINDOW_XFRAME (w), glyph->u.img_id); + if (img != NULL) + *object = img->spec; + y0 -= row->ascent - glyph->ascent; + } +#endif + } + else + { + /* Add extra (default width) columns if clicked after EOL. */ + *x += x0 / WINDOW_FRAME_COLUMN_WIDTH (w); + *width = 0; + *height = row->height; + } } + else + { + x0 = 0; + *x = 0; + *width = *height = 0; + } + + *dx = x0; + *dy = y0; return string; } @@ -6707,3 +6853,6 @@ See `buffer-display-table' for more information. */); Vwindow_system_version = Qnil; } } + +/* arch-tag: 8d812b1f-04a2-4195-a9c4-381f8457a413 + (do not change this comment) */ diff --git a/src/disptab.h b/src/disptab.h index 9b387ba6887..e9c9805ea65 100644 --- a/src/disptab.h +++ b/src/disptab.h @@ -105,3 +105,6 @@ extern Lisp_Object Vglyph_table; #define NULL_GLYPH 00 #define GLYPH_FROM_CHAR(c) (c) + +/* arch-tag: d7f792d2-f59c-4904-a91e-91522e3ab349 + (do not change this comment) */ diff --git a/src/doc.c b/src/doc.c index af5707474c7..e670ad1797a 100644 --- a/src/doc.c +++ b/src/doc.c @@ -1,5 +1,6 @@ /* Record indices of function doc strings stored in a file. - Copyright (C) 1985, 86,93,94,95,97,98,99, 2000 Free Software Foundation, Inc. + Copyright (C) 1985, 86,93,94,95,97,98,99,2000,04 + Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -612,8 +613,7 @@ the same file name is found in the `data-directory'. */) *p = '_'; p++; } -#endif /* not VMS4_4 */ -#ifdef VMS4_4 +#else /* VMS4_4 */ strcpy (name, sys_translate_unix (name)); #endif /* VMS4_4 */ #endif /* VMS */ @@ -660,6 +660,9 @@ the same file name is found in the `data-directory'. */) else if (p[1] == 'F') store_function_docstring (sym, pos + end + 1 - buf); + else if (p[1] == 'S') + ; /* Just a source file name boundary marker. Ignore it. */ + else error ("DOC file invalid at position %d", pos); } diff --git a/src/doprnt.c b/src/doprnt.c index 3bf8248c353..873adca34e0 100644 --- a/src/doprnt.c +++ b/src/doprnt.c @@ -334,3 +334,6 @@ doprnt1 (lispstrings, buffer, bufsize, format, format_end, nargs, args) *bufptr = 0; /* Make sure our string end with a '\0' */ return bufptr - buffer; } + +/* arch-tag: aa0ab528-7c5f-4c73-894c-aa2526a1efb3 + (do not change this comment) */ diff --git a/src/dosfns.c b/src/dosfns.c index f220a442dc8..a64dc31b234 100644 --- a/src/dosfns.c +++ b/src/dosfns.c @@ -651,3 +651,6 @@ If zero, the decimal point key returns the country code specific value. */); dos_decimal_point = 0; } #endif /* MSDOS */ + +/* arch-tag: f5ea8847-a014-42c9-83f5-7738ad640b17 + (do not change this comment) */ diff --git a/src/dosfns.h b/src/dosfns.h index 00e2e1ed1a3..24d214fc1b3 100644 --- a/src/dosfns.h +++ b/src/dosfns.h @@ -43,3 +43,6 @@ extern Lisp_Object Vdos_display_scancodes; extern int msdos_stdcolor_idx P_ ((const char *)); extern Lisp_Object msdos_stdcolor_name P_ ((int)); #endif + +/* arch-tag: a83b8c4c-63c8-451e-9e94-bc72e3e2f8bc + (do not change this comment) */ diff --git a/src/ecrt0.c b/src/ecrt0.c index 17bd4841002..209748c8c9e 100644 --- a/src/ecrt0.c +++ b/src/ecrt0.c @@ -610,3 +610,6 @@ char *__progname; char *__progname; #endif #endif /* __bsdi__ */ + +/* arch-tag: 4025c2fb-d6b1-4d29-b1b6-8100b6bd1e74 + (do not change this comment) */ diff --git a/src/editfns.c b/src/editfns.c index ace0f1f8835..e7a01b24b76 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -3376,7 +3376,7 @@ usage: (format STRING &rest OBJECTS) */) string itself, will not be used. Element NARGS, corresponding to no argument, *will* be assigned to in the case that a `%' and `.' occur after the final format specifier. */ - int *precision = (int *) (alloca(nargs * sizeof (int))); + int *precision = (int *) (alloca((nargs + 1) * sizeof (int))); int longest_format; Lisp_Object val; int arg_intervals = 0; @@ -3430,7 +3430,7 @@ usage: (format STRING &rest OBJECTS) */) /* Make room in result for all the non-%-codes in the control string. */ total = 5 + CONVERTED_BYTE_SIZE (multibyte, args[0]); - /* Allocate the info and discarded tables. */ + /* Allocate the info and discarded tables. */ { int nbytes = nargs * sizeof *info; int i; @@ -4325,7 +4325,7 @@ Transposing beyond buffer boundaries is an error. */) transpose_markers (start1, end1, start2, end2, start1_byte, start1_byte + len1_byte, start2_byte, start2_byte + len2_byte); - fix_overlays_in_range (start1, end2); + fix_start_end_in_overlays (start1, end2); } return Qnil; diff --git a/src/emacs.c b/src/emacs.c index ea68ed24cd4..b27b460fba0 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -1,5 +1,5 @@ /* Fully extensible Emacs, running on Unix, intended for GNU. - Copyright (C) 1985,86,87,93,94,95,97,98,1999,2001,02,2003 + Copyright (C) 1985,86,87,93,94,95,97,98,1999,2001,02,03,2004 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -86,9 +86,18 @@ extern char *index P_ ((const char *, int)); /* Make these values available in GDB, which doesn't see macros. */ +#ifdef USE_LSB_TAG +int gdb_use_lsb = 1; +#else +int gdb_use_lsb = 0; +#endif +#ifdef NO_UNION_TYPE +int gdb_use_union = 0; +#else +int gdb_use_union = 1; +#endif EMACS_INT gdb_valbits = VALBITS; EMACS_INT gdb_gctypebits = GCTYPEBITS; -EMACS_INT gdb_emacs_intbits = sizeof (EMACS_INT) * BITS_PER_CHAR; #ifdef DATA_SEG_BITS EMACS_INT gdb_data_seg_bits = DATA_SEG_BITS; #else @@ -220,6 +229,8 @@ int initial_argc; static void sort_args (); void syms_of_emacs (); +/* MSVC needs each string be shorter than 2048 bytes, so the usage + strings below are split to not overflow this limit. */ #define USAGE1 "\ Usage: %s [OPTION-OR-FILENAME]...\n\ \n\ @@ -232,66 +243,71 @@ read the main documentation for these command-line arguments.\n\ \n\ Initialization options:\n\ \n\ ---batch do not do interactive display; implies -q\n\ ---script FILE run FILE as an Emacs Lisp script.\n\ ---debug-init enable Emacs Lisp debugger during init file\n\ ---help display this help message and exit\n\ ---multibyte, --no-unibyte run Emacs in multibyte mode\n\ ---no-init-file, -q load neither ~/.emacs nor default.el\n\ ---no-shared-memory, -nl do not use shared memory\n\ ---no-site-file do not load site-start.el\n\ ---no-splash do not display a splash screen on startup\n\ ---no-window-system, -nw don't communicate with X, ignoring $DISPLAY\n\ ---terminal, -t DEVICE use DEVICE for terminal I/O\n\ +--batch do not do interactive display; implies -q\n\ +--debug-init enable Emacs Lisp debugger for init file\n\ +--display, -d DISPLAY use X server DISPLAY\n\ +--multibyte, --no-unibyte inhibit the effect of EMACS_UNIBYTE\n\ +--no-desktop do not load a saved desktop\n\ +--no-init-file, -q load neither ~/.emacs nor default.el\n\ +--no-shared-memory, -nl do not use shared memory\n\ +--no-site-file do not load site-start.el\n\ +--no-splash do not display a splash screen on startup\n\ +--no-window-system, -nw don't communicate with X, ignoring $DISPLAY\n\ +--script FILE run FILE as an Emacs Lisp script\n\ +--terminal, -t DEVICE use DEVICE for terminal I/O\n\ --unibyte, --no-multibyte run Emacs in unibyte mode\n\ ---user, -u USER load ~USER/.emacs instead of your own\n\ ---version display version information and exit\n\ -\n\ +--user, -u USER load ~USER/.emacs instead of your own\n\ +\n%s" + +#define USAGE2 "\ Action options:\n\ \n\ -FILE visit FILE using find-file\n\ -+LINE FILE visit FILE using find-file, then go to line LINE\n\ -+LINE:COLUMN FILE visit FILE using find-file, then go to line LINE,\n\ - column COLUMN\n\ ---directory, -L DIR add DIR to variable load-path\n\ ---eval EXPR evaluate Emacs Lisp expression EXPR\n\ ---execute EXPR evaluate Emacs Lisp expression EXPR\n\ ---find-file FILE visit FILE\n\ ---funcall, -f FUNC call Emacs function FUNC with no arguments\n\ ---insert FILE insert contents of FILE into current buffer\n\ ---kill exit without asking for confirmation\n\ ---load, -l FILE load FILE of Emacs Lisp code using the load function\n\ ---visit FILE visit FILE\n\ +FILE visit FILE using find-file\n\ ++LINE FILE visit FILE using find-file, then go to line LINE\n\ ++LINE:COLUMN FILE visit FILE using find-file, then go to line LINE,\n\ + column COLUMN\n\ +--directory, -L DIR add DIR to variable load-path\n\ +--eval EXPR evaluate Emacs Lisp expression EXPR\n\ +--execute EXPR evaluate Emacs Lisp expression EXPR\n\ +--file FILE visit FILE using find-file\n\ +--find-file FILE visit FILE using find-file\n\ +--funcall, -f FUNC call Emacs Lisp function FUNC with no arguments\n\ +--insert FILE insert contents of FILE into current buffer\n\ +--kill exit without asking for confirmation\n\ +--load, -l FILE load Emacs Lisp FILE using the load function\n\ +--visit FILE visit FILE using find-file\n\ \n" -#define USAGE2 "\ +#define USAGE3 "\ Display options:\n\ \n\ ---background-color, -bg COLOR window background color\n\ ---border-color, -bd COLOR main border color\n\ ---border-width, -bw WIDTH width of main border\n\ ---color=MODE color mode for character terminals;\n\ - MODE defaults to `auto', and can also\n\ - be `never', `auto', `always',\n\ - or a mode name like `ansi8'\n\ ---cursor-color, -cr COLOR color of the Emacs cursor indicating point\n\ ---display, -d DISPLAY use X server DISPLAY\n\ ---font, -fn FONT default font; must be fixed-width\n\ ---foreground-color, -fg COLOR window foreground color\n\ ---fullscreen, -fs make first frame fullscreen\n\ ---fullwidth, -fw make the first frame wide as the screen\n\ ---fullheight, -fh make the first frame high as the screen\n\ ---geometry, -g GEOMETRY window geometry\n\ ---iconic start Emacs in iconified state\n\ ---icon-type, -i use picture of gnu for Emacs icon\n\ ---internal-border, -ib WIDTH width between text and main border\n\ ---line-spacing, -lsp PIXELS additional space to put between lines\n\ ---mouse-color, -ms COLOR mouse cursor color in Emacs window\n\ ---name NAME title of main Emacs window\n\ ---reverse-video, -r, -rv switch foreground and background\n\ ---title, -T, -wn TITLE title for Emacs windows\n\ ---vertical-scroll-bars, -vb enable vertical scroll bars\n\ ---xrm XRESOURCES set additional X resources\n\ +--background-color, -bg COLOR window background color\n\ +--border-color, -bd COLOR main border color\n\ +--border-width, -bw WIDTH width of main border\n\ +--color MODE color mode for character terminals;\n\ + MODE defaults to `auto', and can also\n\ + be `never', `auto', `always',\n\ + or a mode name like `ansi8'\n\ +--cursor-color, -cr COLOR color of the Emacs cursor indicating point\n\ +--font, -fn FONT default font; must be fixed-width\n\ +--foreground-color, -fg COLOR window foreground color\n\ +--fullheight, -fh make the first frame high as the screen\n\ +--fullscreen, -fs make first frame fullscreen\n\ +--fullwidth, -fw make the first frame wide as the screen\n\ +--geometry, -g GEOMETRY window geometry\n\ +--horizontal-scroll-bars, -hb enable horizontal scroll bars\n\ +--icon-type, -i use picture of gnu for Emacs icon\n\ +--iconic start Emacs in iconified state\n\ +--internal-border, -ib WIDTH width between text and main border\n\ +--line-spacing, -lsp PIXELS additional space to put between lines\n\ +--mouse-color, -ms COLOR mouse cursor color in Emacs window\n\ +--name NAME title for initial Emacs frame\n\ +--reverse-video, -r, -rv switch foreground and background\n\ +--title, -T TITLE title for initial Emacs frame\n\ +--vertical-scroll-bars, -vb enable vertical scroll bars\n\ +--xrm XRESOURCES set additional X resources\n\ +--help display this help and exit\n\ +--version output version information and exit\n\ \n\ You can generally also specify long option names with a single -; for\n\ example, -batch as well as --batch. You can use any unambiguous\n\ @@ -301,7 +317,7 @@ Various environment variables and window system resources also affect\n\ Emacs' operation. See the main documentation.\n\ \n" -#define USAGE3 "\ +#define USAGE4 "\ Report bugs to %s. First, please see the Bugs\n\ section of the Emacs manual or the file BUGS.\n" @@ -1061,9 +1077,9 @@ main (argc, argv /* Handle the --help option, which gives a usage message. */ if (argmatch (argv, argc, "-help", "--help", 3, NULL, &skip_args)) { - printf (USAGE1, argv[0]); - printf (USAGE2); - printf (USAGE3, bug_reporting_address ()); + printf (USAGE1, argv[0], USAGE2); + printf (USAGE3); + printf (USAGE4, bug_reporting_address ()); exit (0); } @@ -1236,6 +1252,9 @@ main (argc, argv init_window_once (); /* Init the window system. */ init_fileio_once (); /* Must precede any path manipulation. */ +#ifdef HAVE_WINDOW_SYSTEM + init_fringe_once (); /* Swap bitmaps if necessary. */ +#endif /* HAVE_WINDOW_SYSTEM */ } init_alloc (); @@ -1505,6 +1524,10 @@ main (argc, argv #endif /* WINDOWSNT */ syms_of_window (); syms_of_xdisp (); +#ifdef HAVE_WINDOW_SYSTEM + syms_of_fringe (); + syms_of_image (); +#endif /* HAVE_WINDOW_SYSTEM */ #ifdef HAVE_X_WINDOWS syms_of_xterm (); syms_of_xfns (); @@ -1517,12 +1540,14 @@ main (argc, argv #endif #endif /* HAVE_X_WINDOWS */ +#ifdef HAVE_MENUS #ifndef HAVE_NTGUI #ifndef MAC_OS /* Called before init_window_once for Mac OS Classic. */ syms_of_xmenu (); #endif #endif +#endif #ifdef HAVE_NTGUI syms_of_w32term (); @@ -1584,11 +1609,12 @@ main (argc, argv init_vmsproc (); /* And this too. */ #endif /* VMS */ init_sys_modes (); /* Init system terminal modes (RAW or CBREAK, etc.). */ -#if defined (HAVE_X_WINDOWS) || defined (WINDOWSNT) - init_xfns (); -#endif /* HAVE_X_WINDOWS */ init_fns (); init_xdisp (); +#ifdef HAVE_WINDOW_SYSTEM + init_fringe (); + init_image (); +#endif /* HAVE_WINDOW_SYSTEM */ init_macros (); init_editfns (); init_floatfns (); @@ -2002,7 +2028,7 @@ shut_down_emacs (sig, no_x, stuff) fflush (stdout); reset_sys_modes (); if (sig && sig != SIGTERM) - fprintf (stderr, "Fatal error (%d).", sig); + fprintf (stderr, "Fatal error (%d)", sig); } } #else @@ -2407,3 +2433,6 @@ near where the Emacs executable was found. */); doc: /* Most recently used system locale for time. */); Vprevious_system_time_locale = Qnil; } + +/* arch-tag: 7bfd356a-c720-4612-8ab6-aa4222931c2e + (do not change this comment) */ diff --git a/src/epaths.in b/src/epaths.in index 2e7126c328a..00a1a1d04f5 100644 --- a/src/epaths.in +++ b/src/epaths.in @@ -59,3 +59,6 @@ Boston, MA 02111-1307, USA. */ /* Where Emacs should look for the application default file. */ #define PATH_X_DEFAULTS "/usr/lib/X11/%L/%T/%N%C%S:/usr/lib/X11/%l/%T/%N%C%S:/usr/lib/X11/%T/%N%C%S:/usr/lib/X11/%L/%T/%N%S:/usr/lib/X11/%l/%T/%N%S:/usr/lib/X11/%T/%N%S" + +/* arch-tag: d30686c4-629c-4666-9499-beaa69f1641e + (do not change this comment) */ diff --git a/src/eval.c b/src/eval.c index 5061cbc7667..0326a828a81 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1,5 +1,5 @@ /* Evaluator for GNU Emacs Lisp interpreter. - Copyright (C) 1985, 86, 87, 93, 94, 95, 99, 2000, 2001, 2002 + Copyright (C) 1985, 86, 87, 93, 94, 95, 99, 2000, 2001, 02, 2004 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -701,8 +701,8 @@ DEFUN ("defvaralias", Fdefvaralias, Sdefvaralias, 2, 3, 0, doc: /* Make SYMBOL a variable alias for symbol ALIASED. Setting the value of SYMBOL will subsequently set the value of ALIASED, and getting the value of SYMBOL will return the value ALIASED has. -ALIASED nil means remove the alias; SYMBOL is unbound after that. -Third arg DOCSTRING, if non-nil, is documentation for SYMBOL. */) +Third arg DOCSTRING, if non-nil, is documentation for SYMBOL. +The return value is ALIASED. */) (symbol, aliased, docstring) Lisp_Object symbol, aliased, docstring; { @@ -1436,6 +1436,8 @@ A handler for any of those names will get to handle this signal. The symbol `error' should normally be one of them. DATA should be a list. Its elements are printed as part of the error message. +See Info anchor `(elisp)Definition of signal' for some details on how this +error message is constructed. If the signal is handled, DATA is made available to the handler. See also the function `condition-case'. */) (error_symbol, data) @@ -1810,13 +1812,11 @@ then strings and vectors are not accepted. */) /* Lists may represent commands. */ if (!CONSP (fun)) return Qnil; - funcar = Fcar (fun); - if (!SYMBOLP (funcar)) - return Fsignal (Qinvalid_function, Fcons (fun, Qnil)); + funcar = XCAR (fun); if (EQ (funcar, Qlambda)) - return Fassq (Qinteractive, Fcdr (Fcdr (fun))); + return Fassq (Qinteractive, Fcdr (XCDR (fun))); if (EQ (funcar, Qautoload)) - return Fcar (Fcdr (Fcdr (Fcdr (fun)))); + return Fcar (Fcdr (Fcdr (XCDR (fun)))); else return Qnil; } @@ -2641,6 +2641,8 @@ call6 (fn, arg1, arg2, arg3, arg4, arg5, arg6) #endif /* not NO_ARG_ARRAY */ } +/* The caller should GCPRO all the elements of ARGS. */ + DEFUN ("funcall", Ffuncall, Sfuncall, 1, MANY, 0, doc: /* Call first argument as a function, passing remaining arguments to it. Return the value that function returns. @@ -3432,3 +3434,6 @@ The value the function returns is not used. */); defsubr (&Sbacktrace); defsubr (&Sbacktrace_frame); } + +/* arch-tag: 014a07aa-33ab-4a8f-a3d2-ee8a4a9ff7fb + (do not change this comment) */ diff --git a/src/fileio.c b/src/fileio.c index 1454ca921bd..17be7bf4d9c 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -134,6 +134,7 @@ extern int errno; #include "commands.h" extern int use_dialog_box; +extern int use_file_dialog; #ifndef O_WRONLY #define O_WRONLY 1 @@ -2407,7 +2408,7 @@ Also set the file modes of the target file to match the source file. */) CHECK_STRING (newname); if (!NILP (Ffile_directory_p (newname))) - newname = Fexpand_file_name (file, newname); + newname = Fexpand_file_name (Ffile_name_nondirectory (file), newname); else newname = Fexpand_file_name (newname, Qnil); @@ -4654,7 +4655,9 @@ choose_write_coding_system (start, end, filename, { Lisp_Object val; - if (auto_saving) + if (auto_saving + && NILP (Fstring_equal (current_buffer->filename, + current_buffer->auto_save_file_name))) val = Qutf_8_emacs; else if (!NILP (Vcoding_system_for_write)) { @@ -5161,10 +5164,17 @@ This does code conversion according to the value of update_mode_lines++; } else if (quietly) - return Qnil; + { + if (auto_saving + && ! NILP (Fstring_equal (current_buffer->filename, + current_buffer->auto_save_file_name))) + SAVE_MODIFF = MODIFF; + + return Qnil; + } if (!auto_saving) - message_with_string ((! INTEGERP (append) + message_with_string ((INTEGERP (append) ? "Updated %s" : ! NILP (append) ? "Added to %s" @@ -5381,7 +5391,8 @@ e_write (desc, string, start, end, coding) DEFUN ("verify-visited-file-modtime", Fverify_visited_file_modtime, Sverify_visited_file_modtime, 1, 1, 0, doc: /* Return t if last mod time of BUF's visited file matches what BUF records. -This means that the file has not been changed since it was visited or saved. */) +This means that the file has not been changed since it was visited or saved. +See Info node `(elisp)Modification Time' for more details. */) (buf) Lisp_Object buf; { @@ -5437,7 +5448,9 @@ DEFUN ("visited-file-modtime", Fvisited_file_modtime, Svisited_file_modtime, 0, 0, 0, doc: /* Return the current buffer's recorded visited file modification time. The value is a list of the form (HIGH . LOW), like the time values -that `file-attributes' returns. */) +that `file-attributes' returns. If the current buffer has no recorded +file modification time, this function returns 0. +See Info node `(elisp)Modification Time' for more details. */) () { return long_to_cons ((unsigned long) current_buffer->modtime); @@ -5657,11 +5670,14 @@ A non-nil CURRENT-ONLY argument means save only current buffer. */) minibuffer_auto_raise = 0; auto_saving = 1; - /* First, save all files which don't have handlers. If Emacs is - crashing, the handlers may tweak what is causing Emacs to crash - in the first place, and it would be a shame if Emacs failed to - autosave perfectly ordinary files because it couldn't handle some - ange-ftp'd file. */ + /* On first pass, save all files that don't have handlers. + On second pass, save all files that do have handlers. + + If Emacs is crashing, the handlers may tweak what is causing + Emacs to crash in the first place, and it would be a shame if + Emacs failed to autosave perfectly ordinary files because it + couldn't handle some ange-ftp'd file. */ + for (do_handled_files = 0; do_handled_files < 2; do_handled_files++) for (tail = Vbuffer_alist; GC_CONSP (tail); tail = XCDR (tail)) { @@ -5964,6 +5980,7 @@ DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_inte if (SCHARS (name) == 0) return Qt; #endif /* VMS */ + string = Fexpand_file_name (string, dir); if (!NILP (Vread_file_name_predicate)) return call1 (Vread_file_name_predicate, string); return Ffile_exists_p (string); @@ -5972,15 +5989,20 @@ DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_inte DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 6, 0, doc: /* Read file name, prompting with PROMPT and completing in directory DIR. Value is not expanded---you must call `expand-file-name' yourself. -Default name to DEFAULT-FILENAME if user enters a null string. +Default name to DEFAULT-FILENAME if user exits the minibuffer with +the same non-empty string that was inserted by this function. (If DEFAULT-FILENAME is omitted, the visited file name is used, except that if INITIAL is specified, that combined with DIR is used.) +If the user exits with an empty minibuffer, this function returns +an empty string. (This can only happen if the user erased the +pre-inserted contents or if `insert-default-directory' is nil.) Fourth arg MUSTMATCH non-nil means require existing file's name. Non-nil and non-t means also require confirmation after completion. Fifth arg INITIAL specifies text to start with. -If optional sixth arg PREDICATE is non-nil, possible completions and the -resulting file name must satisfy (funcall PREDICATE NAME). -DIR defaults to current buffer's directory default. +If optional sixth arg PREDICATE is non-nil, possible completions and +the resulting file name must satisfy (funcall PREDICATE NAME). +DIR should be an absolute directory name. It defaults to the value of +`default-directory'. If this command was invoked with the mouse, use a file dialog box if `use-dialog-box' is non-nil, and the window system or X toolkit in use @@ -6081,7 +6103,7 @@ provides a file dialog box. */) } count = SPECPDL_INDEX (); -#ifdef VMS +#if defined VMS || defined DOS_NT || defined MAC_OSX specbind (intern ("completion-ignore-case"), Qt); #endif @@ -6094,6 +6116,7 @@ provides a file dialog box. */) #if defined (USE_MOTIF) || defined (HAVE_NTGUI) || defined (USE_GTK) if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event)) && use_dialog_box + && use_file_dialog && have_menus_p ()) { /* If DIR contains a file name, split it. */ @@ -6143,13 +6166,6 @@ provides a file dialog box. */) if (!NILP (tem) && !NILP (default_filename)) val = default_filename; - else if (SCHARS (val) == 0 && NILP (insdef)) - { - if (!NILP (default_filename)) - val = default_filename; - else - error ("No default file name"); - } val = Fsubstitute_in_file_name (val); if (replace_in_history) @@ -6325,7 +6341,20 @@ same format as a regular save would use. */); Vread_file_name_predicate = Qnil; DEFVAR_BOOL ("insert-default-directory", &insert_default_directory, - doc: /* *Non-nil means when reading a filename start with default dir in minibuffer. */); + doc: /* *Non-nil means when reading a filename start with default dir in minibuffer. +If the initial minibuffer contents are non-empty, you can usually +request a default filename by typing RETURN without editing. For some +commands, exiting with an empty minibuffer has a special meaning, +such as making the current buffer visit no file in the case of +`set-visited-file-name'. +If this variable is non-nil, the minibuffer contents are always +initially non-empty and typing RETURN without editing will fetch the +default name, if one is provided. Note however that this default name +is not necessarily the name originally inserted in the minibuffer, if +that is just the default directory. +If this variable is nil, the minibuffer often starts out empty. In +that case you may have to explicitly fetch the next history element to +request the default name. */); insert_default_directory = 1; DEFVAR_BOOL ("vms-stmlf-recfm", &vms_stmlf_recfm, @@ -6473,3 +6502,6 @@ a non-nil value. */); defsubr (&Sunix_sync); #endif } + +/* arch-tag: 64ba3fd7-f844-4fb2-ba4b-427eb928786c + (do not change this comment) */ diff --git a/src/filelock.c b/src/filelock.c index f6108942ba3..b802d0e2a51 100644 --- a/src/filelock.c +++ b/src/filelock.c @@ -770,3 +770,6 @@ syms_of_filelock () } #endif /* CLASH_DETECTION */ + +/* arch-tag: e062676d-50b2-4be0-ab96-197c81b181a1 + (do not change this comment) */ diff --git a/src/filemode.c b/src/filemode.c index d804e94d73c..058880d6699 100644 --- a/src/filemode.c +++ b/src/filemode.c @@ -254,3 +254,6 @@ setst (bits, chars) } #endif } + +/* arch-tag: 4340830c-15a5-47d2-b45f-1d43c45a91bb + (do not change this comment) */ diff --git a/src/firstfile.c b/src/firstfile.c index 295c9b7ff65..faa192257ba 100644 --- a/src/firstfile.c +++ b/src/firstfile.c @@ -33,3 +33,5 @@ extern int initialized; static int * dummy = &initialized; #endif +/* arch-tag: a6c0d2dd-00c3-4ba5-95a5-9c8ab82f39b2 + (do not change this comment) */ diff --git a/src/floatfns.c b/src/floatfns.c index b7d6412fdbf..61879eabe39 100644 --- a/src/floatfns.c +++ b/src/floatfns.c @@ -1,5 +1,5 @@ /* Primitive operations on floating point for GNU Emacs Lisp interpreter. - Copyright (C) 1988, 1993, 1994, 1999 Free Software Foundation, Inc. + Copyright (C) 1988, 1993, 1994, 1999, 2003 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -692,7 +692,7 @@ This is the same as the exponent of a float. */) double f = extract_float (arg); if (f == 0.0) - value = -(VALMASK >> 1); + value = MOST_NEGATIVE_FIXNUM; else { #ifdef HAVE_LOGB @@ -1075,3 +1075,6 @@ syms_of_floatfns () defsubr (&Sround); defsubr (&Struncate); } + +/* arch-tag: be05bf9d-049e-4e31-91b9-e6153d483ae7 + (do not change this comment) */ diff --git a/src/fns.c b/src/fns.c index ea45b9d8dbb..017f8124013 100644 --- a/src/fns.c +++ b/src/fns.c @@ -59,6 +59,10 @@ Boston, MA 02111-1307, USA. */ asked by mouse commands. */ int use_dialog_box; +/* Nonzero enables use of a file dialog for file name + questions asked by mouse commands. */ +int use_file_dialog; + extern int minibuffer_auto_raise; extern Lisp_Object minibuf_window; extern Lisp_Object Vlocale_coding_system; @@ -91,7 +95,7 @@ DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0, DEFUN ("random", Frandom, Srandom, 0, 1, 0, doc: /* Return a pseudo-random number. All integers representable in Lisp are equally likely. - On most systems, this is 28 bits' worth. + On most systems, this is 29 bits' worth. With positive integer argument N, return random number in interval [0,N). With argument t, set the random number seed from the current time and pid. */) (n) @@ -1004,8 +1008,14 @@ string_make_unibyte (string) DEFUN ("string-make-multibyte", Fstring_make_multibyte, Sstring_make_multibyte, 1, 1, 0, doc: /* Return the multibyte equivalent of STRING. -The function `unibyte-char-to-multibyte' is used to convert -each unibyte character to a multibyte character. */) +If STRING is unibyte and contains non-ASCII characters, the function +`unibyte-char-to-multibyte' is used to convert each unibyte character +to a multibyte character. In this case, the returned string is a +newly created string with no text properties. If STRING is multibyte +or entirely ASCII, it is returned unchanged. In particular, when +STRING is unibyte and entirely ASCII, the returned string is unibyte. +\(When the characters are all ASCII, Emacs primitives will treat the +string the same way whether it is unibyte or multibyte.) */) (string) Lisp_Object string; { @@ -1035,8 +1045,7 @@ DEFUN ("string-as-unibyte", Fstring_as_unibyte, Sstring_as_unibyte, If STRING is unibyte, the result is STRING itself. Otherwise it is a newly created string, with no text properties. If STRING is multibyte and contains a character of charset -`eight-bit-control' or `eight-bit-graphic', it is converted to the -corresponding single byte. */) +`eight-bit', it is converted to the corresponding single byte. */) (string) Lisp_Object string; { @@ -1408,7 +1417,7 @@ whose car is ELT. */) DEFUN ("assq", Fassq, Sassq, 2, 2, 0, doc: /* Return non-nil if KEY is `eq' to the car of an element of LIST. -The value is actually the element of LIST whose car is KEY. +The value is actually the first element of LIST whose car is KEY. Elements of LIST that are not conses are ignored. */) (key, list) Lisp_Object key, list; @@ -1465,7 +1474,7 @@ assq_no_quit (key, list) DEFUN ("assoc", Fassoc, Sassoc, 2, 2, 0, doc: /* Return non-nil if KEY is `equal' to the car of an element of LIST. -The value is actually the element of LIST whose car equals KEY. */) +The value is actually the first element of LIST whose car equals KEY. */) (key, list) Lisp_Object key, list; { @@ -1509,7 +1518,7 @@ The value is actually the element of LIST whose car equals KEY. */) DEFUN ("rassq", Frassq, Srassq, 2, 2, 0, doc: /* Return non-nil if KEY is `eq' to the cdr of an element of LIST. -The value is actually the element of LIST whose cdr is KEY. */) +The value is actually the first element of LIST whose cdr is KEY. */) (key, list) register Lisp_Object key; Lisp_Object list; @@ -1551,7 +1560,7 @@ The value is actually the element of LIST whose cdr is KEY. */) DEFUN ("rassoc", Frassoc, Srassoc, 2, 2, 0, doc: /* Return non-nil if KEY is `equal' to the cdr of an element of LIST. -The value is actually the element of LIST whose cdr equals KEY. */) +The value is actually the first element of LIST whose cdr equals KEY. */) (key, list) Lisp_Object key, list; { @@ -1754,7 +1763,7 @@ to be sure of changing the value of `foo'. */) DEFUN ("nreverse", Fnreverse, Snreverse, 1, 1, 0, doc: /* Reverse LIST by modifying cdr pointers. -Returns the beginning of the reversed list. */) +Return the reversed list. */) (list) Lisp_Object list; { @@ -1777,7 +1786,7 @@ Returns the beginning of the reversed list. */) } DEFUN ("reverse", Freverse, Sreverse, 1, 1, 0, - doc: /* Reverse LIST, copying. Returns the beginning of the reversed list. + doc: /* Reverse LIST, copying. Return the reversed list. See also the function `nreverse', which is used more often. */) (list) Lisp_Object list; @@ -2052,13 +2061,27 @@ Symbols must match exactly. */) (o1, o2) register Lisp_Object o1, o2; { - return internal_equal (o1, o2, 0) ? Qt : Qnil; + return internal_equal (o1, o2, 0, 0) ? Qt : Qnil; +} + +DEFUN ("equal-including-properties", Fequal_including_properties, Sequal_including_properties, 2, 2, 0, + doc: /* Return t if two Lisp objects have similar structure and contents. +This is like `equal' except that it compares the text properties +of strings. (`equal' ignores text properties.) */) + (o1, o2) + register Lisp_Object o1, o2; +{ + return internal_equal (o1, o2, 0, 1) ? Qt : Qnil; } +/* DEPTH is current depth of recursion. Signal an error if it + gets too deep. + PROPS, if non-nil, means compare string text properties too. */ + static int -internal_equal (o1, o2, depth) +internal_equal (o1, o2, depth, props) register Lisp_Object o1, o2; - int depth; + int depth, props; { if (depth > 200) error ("Stack overflow in equal"); @@ -2073,10 +2096,18 @@ internal_equal (o1, o2, depth) switch (XTYPE (o1)) { case Lisp_Float: - return (extract_float (o1) == extract_float (o2)); + { + double d1, d2; + + d1 = extract_float (o1); + d2 = extract_float (o2); + /* If d is a NaN, then d != d. Two NaNs should be `equal' even + though they are not =. */ + return d1 == d2 || (d1 != d1 && d2 != d2); + } case Lisp_Cons: - if (!internal_equal (XCAR (o1), XCAR (o2), depth + 1)) + if (!internal_equal (XCAR (o1), XCAR (o2), depth + 1, props)) return 0; o1 = XCDR (o1); o2 = XCDR (o2); @@ -2088,7 +2119,7 @@ internal_equal (o1, o2, depth) if (OVERLAYP (o1)) { if (!internal_equal (OVERLAY_START (o1), OVERLAY_START (o2), - depth + 1) + depth + 1, props) || !internal_equal (OVERLAY_END (o1), OVERLAY_END (o2), depth + 1)) return 0; @@ -2106,8 +2137,8 @@ internal_equal (o1, o2, depth) case Lisp_Vectorlike: { - register int i, size; - size = XVECTOR (o1)->size; + register int i; + EMACS_INT size = XVECTOR (o1)->size; /* Pseudovectors have the type encoded in the size field, so this test actually checks that the objects have the same type as well as the same size. */ @@ -2143,7 +2174,7 @@ internal_equal (o1, o2, depth) Lisp_Object v1, v2; v1 = XVECTOR (o1)->contents [i]; v2 = XVECTOR (o2)->contents [i]; - if (!internal_equal (v1, v2, depth + 1)) + if (!internal_equal (v1, v2, depth + 1, props)) return 0; } return 1; @@ -2158,6 +2189,8 @@ internal_equal (o1, o2, depth) if (bcmp (SDATA (o1), SDATA (o2), SBYTES (o1))) return 0; + if (props && !compare_string_intervals (o1, o2)) + return 0; return 1; case Lisp_Int: @@ -2230,8 +2263,15 @@ ARRAY is a vector, string, char-table, or bool-vector. */) = (XBOOL_VECTOR (array)->size + BITS_PER_CHAR - 1) / BITS_PER_CHAR; charval = (! NILP (item) ? -1 : 0); - for (index = 0; index < size_in_chars; index++) + for (index = 0; index < size_in_chars - 1; index++) p[index] = charval; + if (index < size_in_chars) + { + /* Mask out bits beyond the vector size. */ + if (XBOOL_VECTOR (array)->size % BITS_PER_CHAR) + charval &= (1 << (XBOOL_VECTOR (array)->size % BITS_PER_CHAR)) - 1; + p[index] = charval; + } } else { @@ -2798,8 +2838,8 @@ DEFUN ("require", Frequire, Srequire, 1, 3, 0, If FEATURE is not a member of the list `features', then the feature is not loaded; so load the file FILENAME. If FILENAME is omitted, the printname of FEATURE is used as the file name, -and `load' will try to load this name appended with the suffix `.elc', -`.el' or the unmodified name, in that order. +and `load' will try to load this name appended with the suffix `.elc' or +`.el', in that order. The name without appended suffix will not be used. If the optional third argument NOERROR is non-nil, then return nil if the file is not found instead of signaling an error. Normally the return value is FEATURE. @@ -3749,7 +3789,7 @@ hashfn_eq (h, key) Lisp_Object key; { unsigned hash = XUINT (key) ^ XGCTYPE (key); - xassert ((hash & ~VALMASK) == 0); + xassert ((hash & ~INTMASK) == 0); return hash; } @@ -3768,7 +3808,7 @@ hashfn_eql (h, key) hash = sxhash (key, 0); else hash = XUINT (key) ^ XGCTYPE (key); - xassert ((hash & ~VALMASK) == 0); + xassert ((hash & ~INTMASK) == 0); return hash; } @@ -3783,7 +3823,7 @@ hashfn_equal (h, key) Lisp_Object key; { unsigned hash = sxhash (key, 0); - xassert ((hash & ~VALMASK) == 0); + xassert ((hash & ~INTMASK) == 0); return hash; } @@ -3970,7 +4010,7 @@ maybe_resize_hash_table (h) index_size = next_almost_prime ((int) (new_size / XFLOATINT (h->rehash_threshold))); - if (max (index_size, 2 * new_size) & ~VALMASK) + if (max (index_size, 2 * new_size) > MOST_POSITIVE_FIXNUM) error ("Hash table too large to resize"); h->key_and_value = larger_vector (h->key_and_value, 2 * new_size, Qnil); @@ -4060,7 +4100,7 @@ hash_put (h, key, value, hash) { int start_of_bucket, i; - xassert ((hash & ~VALMASK) == 0); + xassert ((hash & ~INTMASK) == 0); /* Increment count after resizing because resizing may fail. */ maybe_resize_hash_table (h); @@ -4345,7 +4385,7 @@ sxhash_string (ptr, len) hash = ((hash << 3) + (hash >> 28) + c); } - return hash & VALMASK; + return hash & INTMASK; } @@ -4413,7 +4453,7 @@ sxhash_bool_vector (vec) /* Return a hash code for OBJ. DEPTH is the current depth in the Lisp - structure. Value is an unsigned integer clipped to VALMASK. */ + structure. Value is an unsigned integer clipped to INTMASK. */ unsigned sxhash (obj, depth) @@ -4477,7 +4517,7 @@ sxhash (obj, depth) abort (); } - return hash & VALMASK; + return hash & INTMASK; } @@ -4903,12 +4943,18 @@ guesswork fails. Normally, an error is signaled in such case. */) } else { + struct buffer *prev = current_buffer; + + record_unwind_protect (Fset_buffer, Fcurrent_buffer ()); + CHECK_BUFFER (object); bp = XBUFFER (object); + if (bp != current_buffer) + set_buffer_internal (bp); if (NILP (start)) - b = BUF_BEGV (bp); + b = BEGV; else { CHECK_NUMBER_COERCE_MARKER (start); @@ -4916,7 +4962,7 @@ guesswork fails. Normally, an error is signaled in such case. */) } if (NILP (end)) - e = BUF_ZV (bp); + e = ZV; else { CHECK_NUMBER_COERCE_MARKER (end); @@ -4926,7 +4972,7 @@ guesswork fails. Normally, an error is signaled in such case. */) if (b > e) temp = b, b = e, e = temp; - if (!(BUF_BEGV (bp) <= b && e <= BUF_ZV (bp))) + if (!(BEGV <= b && e <= ZV)) args_out_of_range (start, end); if (NILP (coding_system)) @@ -4993,6 +5039,11 @@ guesswork fails. Normally, an error is signaled in such case. */) } object = make_buffer_string (b, e, 0); + if (prev != current_buffer) + set_buffer_internal (prev); + /* Discard the unwind protect for recovering the current + buffer. */ + specpdl_ptr--; if (STRING_MULTIBYTE (object)) object = code_convert_string (object, coding_system, Qnil, 1, 0, 0); @@ -5105,6 +5156,13 @@ This applies to `y-or-n-p' and `yes-or-no-p' questions asked by commands invoked by mouse clicks and mouse menu items. */); use_dialog_box = 1; + DEFVAR_BOOL ("use-file-dialog", &use_file_dialog, + doc: /* *Non-nil means mouse commands use a file dialog to ask for files. +This applies to commands from menus and tool bar buttons. The value of +`use-dialog-box' takes precedence over this variable, so a file dialog is only +used if both `use-dialog-box' and this variable are non-nil. */); + use_file_dialog = 1; + defsubr (&Sidentity); defsubr (&Srandom); defsubr (&Slength); @@ -5146,6 +5204,7 @@ invoked by mouse clicks and mouse menu items. */); defsubr (&Slax_plist_get); defsubr (&Slax_plist_put); defsubr (&Sequal); + defsubr (&Sequal_including_properties); defsubr (&Sfillarray); defsubr (&Sclear_string); defsubr (&Snconc); @@ -5176,3 +5235,6 @@ init_fns () { Vweak_hash_tables = Qnil; } + +/* arch-tag: 787f8219-5b74-46bd-8469-7e1cc475fa31 + (do not change this comment) */ diff --git a/src/frame.c b/src/frame.c index 546c56eab97..c515b565670 100644 --- a/src/frame.c +++ b/src/frame.c @@ -114,6 +114,7 @@ Lisp_Object Qface_set_after_frame_default; Lisp_Object Vterminal_frame; Lisp_Object Vdefault_frame_alist; +Lisp_Object Vdefault_frame_scroll_bars; Lisp_Object Vmouse_position_function; Lisp_Object Vmouse_highlight; Lisp_Object Vdelete_frame_functions; @@ -1278,6 +1279,8 @@ The functions are run with one arg, the frame to be deleted. */) if (f->namebuf) xfree (f->namebuf); + if (f->decode_mode_spec_buffer) + xfree (f->decode_mode_spec_buffer); if (FRAME_INSERT_COST (f)) xfree (FRAME_INSERT_COST (f)); if (FRAME_DELETEN_COST (f)) @@ -2015,7 +2018,7 @@ store_frame_param (f, prop, val) if (EQ (prop, Qminibuffer) && WINDOWP (val)) { if (! MINI_WINDOW_P (XWINDOW (val))) - error ("Surrogate minibuffer windows must be minibuffer windows."); + error ("Surrogate minibuffer windows must be minibuffer windows"); if ((FRAME_HAS_MINIBUF_P (f) || FRAME_MINIBUF_ONLY_P (f)) && !EQ (val, f->minibuffer_window)) @@ -2590,32 +2593,6 @@ x_fullscreen_adjust (f, width, height, top_pos, left_pos) } -/* Really try to move where we want to be in case of fullscreen. Some WMs - moves the window where we tell them. Some (mwm, twm) moves the outer - window manager window there instead. - Try to compensate for those WM here. */ - -static void -x_fullscreen_move (f, new_top, new_left) - struct frame *f; - int new_top; - int new_left; -{ - if (new_top != f->top_pos || new_left != f->left_pos) - { - int move_x = new_left; - int move_y = new_top; - -#ifdef HAVE_X_WINDOWS - move_x += FRAME_X_OUTPUT (f)->x_pixels_outer_diff; - move_y += FRAME_X_OUTPUT (f)->y_pixels_outer_diff; -#endif - - f->want_fullscreen |= FULLSCREEN_MOVE_WAIT; - x_set_offset (f, move_x, move_y, 1); - } -} - /* Change the parameters of frame F as specified by ALIST. If a parameter is not specially recognized, do nothing special; otherwise call the `x_set_...' function for that parameter. @@ -2811,7 +2788,8 @@ x_set_frame_parameters (f, alist) int new_left, new_top; x_fullscreen_adjust (f, &width, &height, &new_top, &new_left); - x_fullscreen_move (f, new_top, new_left); + if (new_top != f->top_pos || new_left != f->left_pos) + x_set_offset (f, new_left, new_top, 1); } #endif @@ -3217,13 +3195,11 @@ x_set_vertical_scroll_bars (f, arg, oldval) ? vertical_scroll_bar_left : EQ (Qright, arg) ? vertical_scroll_bar_right -#ifdef HAVE_NTGUI - /* MS-Windows has scroll bars on the right by default. */ - : vertical_scroll_bar_right -#else - : vertical_scroll_bar_left -#endif - ); + : EQ (Qleft, Vdefault_frame_scroll_bars) + ? vertical_scroll_bar_left + : EQ (Qright, Vdefault_frame_scroll_bars) + ? vertical_scroll_bar_right + : vertical_scroll_bar_none); /* We set this parameter before creating the X window for the frame, so we can get the geometry right from the start. @@ -4032,6 +4008,19 @@ The `menu-bar-lines' element of the list controls whether new frames Setting this variable does not affect existing frames, only new ones. */); Vdefault_frame_alist = Qnil; + DEFVAR_LISP ("default-frame-scroll-bars", &Vdefault_frame_scroll_bars, + doc: /* Default position of scroll bars on this window-system. */); +#ifdef HAVE_WINDOW_SYSTEM +#if defined(HAVE_NTGUI) || defined(HAVE_CARBON) + /* MS-Windows has scroll bars on the right by default. */ + Vdefault_frame_scroll_bars = Qright; +#else + Vdefault_frame_scroll_bars = Qleft; +#endif +#else + Vdefault_frame_scroll_bars = Qnil; +#endif + Qinhibit_default_face_x_resources = intern ("inhibit-default-face-x-resources"); staticpro (&Qinhibit_default_face_x_resources); @@ -4134,3 +4123,6 @@ This variable is local to the current terminal and cannot be buffer-local. */); #endif } + +/* arch-tag: 7dbf2c69-9aad-45f8-8296-db893d6dd039 + (do not change this comment) */ diff --git a/src/frame.h b/src/frame.h index b4ddf5136d5..42227d59fee 100644 --- a/src/frame.h +++ b/src/frame.h @@ -452,6 +452,10 @@ struct frame Clear the frame in clear_garbaged_frames if set. */ unsigned resized_p : 1; + /* Set to non-zero in when we want for force a flush_display in + update_frame, usually after resizing the frame. */ + unsigned force_flush_display_p : 1; + /* Set to non-zero if the default face for the frame has been realized. Reset to zero whenever the default face changes. Used to see the difference between a font change and face change. */ @@ -795,9 +799,6 @@ extern Lisp_Object Vdefault_frame_alist; extern Lisp_Object Vterminal_frame; extern Lisp_Object Vmouse_highlight; - -enum text_cursor_kinds get_specified_cursor_type P_ ((Lisp_Object, int *)); -enum text_cursor_kinds get_window_cursor_type P_ ((struct window *, int *, int *)); /* The currently selected frame. */ @@ -1023,7 +1024,6 @@ enum FULLSCREEN_HEIGHT = 2, FULLSCREEN_BOTH = 3, FULLSCREEN_WAIT = 4, - FULLSCREEN_MOVE_WAIT = 8, }; @@ -1078,3 +1078,6 @@ extern void validate_x_resource_name P_ ((void)); #endif /* HAVE_WINDOW_SYSTEM */ #endif /* not EMACS_FRAME_H */ + +/* arch-tag: 0df048ee-e6bf-4f48-bd56-e3cd055dd8c4 + (do not change this comment) */ diff --git a/src/fringe.c b/src/fringe.c new file mode 100644 index 00000000000..3f040699009 --- /dev/null +++ b/src/fringe.c @@ -0,0 +1,1358 @@ +/* Fringe handling (split from xdisp.c). + Copyright (C) 1985,86,87,88,93,94,95,97,98,99,2000,01,02,03,04 + Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include <config.h> +#include <stdio.h> + +#include "lisp.h" +#include "frame.h" +#include "window.h" +#include "dispextern.h" +#include "buffer.h" +#include "blockinput.h" + +#ifdef HAVE_WINDOW_SYSTEM + +extern Lisp_Object Qtop, Qbottom, Qcenter; + +/* Non-nil means that newline may flow into the right fringe. */ + +Lisp_Object Voverflow_newline_into_fringe; + + +enum fringe_bitmap_type +{ + NO_FRINGE_BITMAP = 0, + UNDEF_FRINGE_BITMAP, + LEFT_TRUNCATION_BITMAP, + RIGHT_TRUNCATION_BITMAP, + UP_ARROW_BITMAP, + DOWN_ARROW_BITMAP, + CONTINUED_LINE_BITMAP, + CONTINUATION_LINE_BITMAP, + OVERLAY_ARROW_BITMAP, + TOP_LEFT_ANGLE_BITMAP, + TOP_RIGHT_ANGLE_BITMAP, + BOTTOM_LEFT_ANGLE_BITMAP, + BOTTOM_RIGHT_ANGLE_BITMAP, + LEFT_BRACKET_BITMAP, + RIGHT_BRACKET_BITMAP, + FILLED_BOX_CURSOR_BITMAP, + HOLLOW_BOX_CURSOR_BITMAP, + HOLLOW_SQUARE_BITMAP, + BAR_CURSOR_BITMAP, + HBAR_CURSOR_BITMAP, + ZV_LINE_BITMAP, + MAX_STANDARD_FRINGE_BITMAPS +}; + +enum fringe_bitmap_align +{ + ALIGN_BITMAP_CENTER = 0, + ALIGN_BITMAP_TOP, + ALIGN_BITMAP_BOTTOM +}; + +struct fringe_bitmap +{ + unsigned short *bits; + unsigned height : 8; + unsigned width : 8; + unsigned period : 8; + unsigned align : 2; + unsigned dynamic : 1; +}; + + +/*********************************************************************** + Fringe bitmaps + ***********************************************************************/ + +/* Undefined bitmap. A question mark. */ +/* + ..xxxx.. + .xxxxxx. + xx....xx + xx....xx + ....xx.. + ...xx... + ...xx... + ........ + ...xx... + ...xx... +*/ +static unsigned short unknown_bits[] = { + 0x3c, 0x7e, 0x7e, 0x0c, 0x18, 0x18, 0x00, 0x18, 0x18}; + +/* An arrow like this: `<-'. */ +/* + ...xx... + ..xx.... + .xx..... + xxxxxx.. + xxxxxx.. + .xx..... + ..xx.... + ...xx... +*/ +static unsigned short left_arrow_bits[] = { + 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18}; + + +/* Right truncation arrow bitmap `->'. */ +/* + ...xx... + ....xx.. + .....xx. + ..xxxxxx + ..xxxxxx + .....xx. + ....xx.. + ...xx... +*/ +static unsigned short right_arrow_bits[] = { + 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18}; + + +/* Up arrow bitmap. */ +/* + ...xx... + ..xxxx.. + .xxxxxx. + xxxxxxxx + ...xx... + ...xx... + ...xx... + ...xx... +*/ +static unsigned short up_arrow_bits[] = { + 0x18, 0x3c, 0x7e, 0xff, 0x18, 0x18, 0x18, 0x18}; + + +/* Down arrow bitmap. */ +/* + ...xx... + ...xx... + ...xx... + ...xx... + xxxxxxxx + .xxxxxx. + ..xxxx.. + ...xx... +*/ +static unsigned short down_arrow_bits[] = { + 0x18, 0x18, 0x18, 0x18, 0xff, 0x7e, 0x3c, 0x18}; + +/* Marker for continued lines. */ +/* + ..xxxx.. + ..xxxxx. + ......xx + ..x..xxx + ..xxxxxx + ..xxxxx. + ..xxxx.. + ..xxxxx. +*/ +static unsigned short continued_bits[] = { + 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e}; + +/* Marker for continuation lines. */ +/* + ..xxxx.. + .xxxxx.. + xx...... + xxx..x.. + xxxxxx.. + .xxxxx.. + ..xxxx.. + .xxxxx.. +*/ +static unsigned short continuation_bits[] = { + 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c}; + +/* Overlay arrow bitmap. A triangular arrow. */ +/* + xx...... + xxxx.... + xxxxx... + xxxxxx.. + xxxxxx.. + xxxxx... + xxxx.... + xx...... +*/ +static unsigned short ov_bits[] = { + 0xc0, 0xf0, 0xf8, 0xfc, 0xfc, 0xf8, 0xf0, 0xc0}; + +#if 0 +/* Reverse Overlay arrow bitmap. A triangular arrow. */ +/* + ......xx + ....xxxx + ...xxxxx + ..xxxxxx + ..xxxxxx + ...xxxxx + ....xxxx + ......xx +*/ +static unsigned short rev_ov_bits[] = { + 0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03}; +#endif + +/* First line bitmap. An top-left angle. */ +/* + xxxxxx.. + xxxxxx.. + xx...... + xx...... + xx...... + xx...... + xx...... + ........ +*/ +static unsigned short top_left_angle_bits[] = { + 0xfc, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00}; + +/* First line bitmap. An right-up angle. */ +/* + ..xxxxxx + ..xxxxxx + ......xx + ......xx + ......xx + ......xx + ......xx + ........ +*/ +static unsigned short top_right_angle_bits[] = { + 0x3f, 0x3f, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00}; + +/* Last line bitmap. An left-down angle. */ +/* + ........ + xx...... + xx...... + xx...... + xx...... + xx...... + xxxxxx.. + xxxxxx.. +*/ +static unsigned short bottom_left_angle_bits[] = { + 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xfc}; + +/* Last line bitmap. An right-down angle. */ +/* + ........ + ......xx + ......xx + ......xx + ......xx + ......xx + ..xxxxxx + ..xxxxxx +*/ +static unsigned short bottom_right_angle_bits[] = { + 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x3f, 0x3f}; + +/* First/last line bitmap. An left bracket. */ +/* + xxxxxx.. + xxxxxx.. + xx...... + xx...... + xx...... + xx...... + xx...... + xx...... + xxxxxx.. + xxxxxx.. +*/ +static unsigned short left_bracket_bits[] = { + 0xfc, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xfc}; + +/* First/last line bitmap. An right bracket. */ +/* + ..xxxxxx + ..xxxxxx + ......xx + ......xx + ......xx + ......xx + ......xx + ......xx + ..xxxxxx + ..xxxxxx +*/ +static unsigned short right_bracket_bits[] = { + 0x3f, 0x3f, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x3f, 0x3f}; + +/* Filled box cursor bitmap. A filled box; max 13 pixels high. */ +/* + xxxxxxx. + xxxxxxx. + xxxxxxx. + xxxxxxx. + xxxxxxx. + xxxxxxx. + xxxxxxx. + xxxxxxx. + xxxxxxx. + xxxxxxx. + xxxxxxx. + xxxxxxx. + xxxxxxx. +*/ +static unsigned short filled_box_cursor_bits[] = { + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe}; + +/* Hollow box cursor bitmap. A hollow box; max 13 pixels high. */ +/* + xxxxxxx. + x.....x. + x.....x. + x.....x. + x.....x. + x.....x. + x.....x. + x.....x. + x.....x. + x.....x. + x.....x. + x.....x. + xxxxxxx. +*/ +static unsigned short hollow_box_cursor_bits[] = { + 0xfe, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0xfe}; + +/* Bar cursor bitmap. A vertical bar; max 13 pixels high. */ +/* + xx...... + xx...... + xx...... + xx...... + xx...... + xx...... + xx...... + xx...... + xx...... + xx...... + xx...... + xx...... + xx...... +*/ +static unsigned short bar_cursor_bits[] = { + 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0}; + +/* HBar cursor bitmap. A horisontal bar; 2 pixels high. */ +/* + xxxxxxx. + xxxxxxx. +*/ +static unsigned short hbar_cursor_bits[] = { + 0xfe, 0xfe}; + + +/* Bitmap drawn to indicate lines not displaying text if + `indicate-empty-lines' is non-nil. */ +/* + ........ + ..xxxx.. + ........ + ........ + ..xxxx.. + ........ +*/ +static unsigned short zv_bits[] = { + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00}; + +/* Hollow square bitmap. */ +/* + .xxxxxx. + .x....x. + .x....x. + .x....x. + .x....x. + .xxxxxx. +*/ +static unsigned short hollow_square_bits[] = { + 0x7e, 0x42, 0x42, 0x42, 0x42, 0x7e}; + + +#define BYTES_PER_BITMAP_ROW (sizeof (unsigned short)) +#define STANDARD_BITMAP_HEIGHT(bits) (sizeof (bits)/BYTES_PER_BITMAP_ROW) +#define FRBITS(bits) bits, STANDARD_BITMAP_HEIGHT (bits) + +struct fringe_bitmap standard_bitmaps[MAX_STANDARD_FRINGE_BITMAPS] = +{ + { NULL, 0, 0, 0, 0, 0 }, /* NO_FRINGE_BITMAP */ + { FRBITS (unknown_bits), 8, 0, ALIGN_BITMAP_CENTER, 0 }, + { FRBITS (left_arrow_bits), 8, 0, ALIGN_BITMAP_CENTER, 0 }, + { FRBITS (right_arrow_bits), 8, 0, ALIGN_BITMAP_CENTER, 0 }, + { FRBITS (up_arrow_bits), 8, 0, ALIGN_BITMAP_TOP, 0 }, + { FRBITS (down_arrow_bits), 8, 0, ALIGN_BITMAP_BOTTOM, 0 }, + { FRBITS (continued_bits), 8, 0, ALIGN_BITMAP_CENTER, 0 }, + { FRBITS (continuation_bits), 8, 0, ALIGN_BITMAP_CENTER, 0 }, + { FRBITS (ov_bits), 8, 0, ALIGN_BITMAP_CENTER, 0 }, + { FRBITS (top_left_angle_bits), 8, 0, ALIGN_BITMAP_TOP, 0 }, + { FRBITS (top_right_angle_bits), 8, 0, ALIGN_BITMAP_TOP, 0 }, + { FRBITS (bottom_left_angle_bits), 8, 0, ALIGN_BITMAP_BOTTOM, 0 }, + { FRBITS (bottom_right_angle_bits), 8, 0, ALIGN_BITMAP_BOTTOM, 0 }, + { FRBITS (left_bracket_bits), 8, 0, ALIGN_BITMAP_CENTER, 0 }, + { FRBITS (right_bracket_bits), 8, 0, ALIGN_BITMAP_CENTER, 0 }, + { FRBITS (filled_box_cursor_bits), 8, 0, ALIGN_BITMAP_CENTER, 0 }, + { FRBITS (hollow_box_cursor_bits), 8, 0, ALIGN_BITMAP_CENTER, 0 }, + { FRBITS (hollow_square_bits), 8, 0, ALIGN_BITMAP_CENTER, 0 }, + { FRBITS (bar_cursor_bits), 8, 0, ALIGN_BITMAP_CENTER, 0 }, + { FRBITS (hbar_cursor_bits), 8, 0, ALIGN_BITMAP_BOTTOM, 0 }, + { FRBITS (zv_bits), 8, 3, ALIGN_BITMAP_TOP, 0 }, +}; + +static struct fringe_bitmap *fringe_bitmaps[MAX_FRINGE_BITMAPS]; +static unsigned fringe_faces[MAX_FRINGE_BITMAPS]; + +static int max_used_fringe_bitmap = MAX_STANDARD_FRINGE_BITMAPS; + +/* Return 1 if FRINGE_ID is a valid fringe bitmap id. */ + +int +valid_fringe_bitmap_id_p (fringe_id) + int fringe_id; +{ + return (fringe_id >= NO_FRINGE_BITMAP + && fringe_id < max_used_fringe_bitmap + && (fringe_id < MAX_STANDARD_FRINGE_BITMAPS + || fringe_bitmaps[fringe_id] != NULL)); +} + +/* Draw the bitmap WHICH in one of the left or right fringes of + window W. ROW is the glyph row for which to display the bitmap; it + determines the vertical position at which the bitmap has to be + drawn. + LEFT_P is 1 for left fringe, 0 for right fringe. +*/ + +void +draw_fringe_bitmap_1 (w, row, left_p, overlay, which) + struct window *w; + struct glyph_row *row; + int left_p, overlay; + enum fringe_bitmap_type which; +{ + struct frame *f = XFRAME (WINDOW_FRAME (w)); + struct draw_fringe_bitmap_params p; + struct fringe_bitmap *fb; + int period; + int face_id = DEFAULT_FACE_ID; + + p.cursor_p = 0; + p.overlay_p = (overlay & 1) == 1; + p.cursor_p = (overlay & 2) == 2; + + if (which != NO_FRINGE_BITMAP) + { + } + else if (left_p) + { + which = row->left_fringe_bitmap; + face_id = row->left_fringe_face_id; + } + else + { + which = row->right_fringe_bitmap; + face_id = row->right_fringe_face_id; + } + + if (face_id == DEFAULT_FACE_ID) + face_id = fringe_faces[which]; + + fb = fringe_bitmaps[which]; + if (fb == NULL) + fb = &standard_bitmaps[which < MAX_STANDARD_FRINGE_BITMAPS + ? which : UNDEF_FRINGE_BITMAP]; + + period = fb->period; + + /* Convert row to frame coordinates. */ + p.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); + + p.which = which; + p.bits = fb->bits; + p.wd = fb->width; + + p.h = fb->height; + p.dh = (period > 0 ? (p.y % period) : 0); + p.h -= p.dh; + /* Clip bitmap if too high. */ + if (p.h > row->height) + p.h = row->height; + + p.face = FACE_FROM_ID (f, face_id); + + if (p.face == NULL) + { + /* Why does this happen? ++kfs */ + return; + } + + PREPARE_FACE_FOR_DISPLAY (f, p.face); + + /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill + the fringe. */ + p.bx = -1; + if (left_p) + { + int wd = WINDOW_LEFT_FRINGE_WIDTH (w); + int x = window_box_left (w, (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) + ? LEFT_MARGIN_AREA + : TEXT_AREA)); + if (p.wd > wd) + p.wd = wd; + p.x = x - p.wd - (wd - p.wd) / 2; + + if (p.wd < wd || row->height > p.h) + { + /* If W has a vertical border to its left, don't draw over it. */ + wd -= ((!WINDOW_LEFTMOST_P (w) + && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w)) + ? 1 : 0); + p.bx = x - wd; + p.nx = wd; + } + } + else + { + int x = window_box_right (w, + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) + ? RIGHT_MARGIN_AREA + : TEXT_AREA)); + int wd = WINDOW_RIGHT_FRINGE_WIDTH (w); + if (p.wd > wd) + p.wd = wd; + p.x = x + (wd - p.wd) / 2; + /* Clear right fringe if no bitmap to draw of if bitmap doesn't fill + the fringe. */ + if (p.wd < wd || row->height > p.h) + { + p.bx = x; + p.nx = wd; + } + } + + if (p.bx >= 0) + { + int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w); + + p.by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, row->y)); + p.ny = row->visible_height; + } + + /* Adjust y to the offset in the row to start drawing the bitmap. */ + switch (fb->align) + { + case ALIGN_BITMAP_CENTER: + p.y += (row->height - p.h) / 2; + break; + case ALIGN_BITMAP_BOTTOM: + p.h = fb->height; + p.y += (row->visible_height - p.h); + break; + case ALIGN_BITMAP_TOP: + break; + } + + rif->draw_fringe_bitmap (w, row, &p); +} + +void +draw_fringe_bitmap (w, row, left_p) + struct window *w; + struct glyph_row *row; + int left_p; +{ + int overlay = 0; + + if (!left_p && row->cursor_in_fringe_p) + { + int cursor = NO_FRINGE_BITMAP; + + switch (w->phys_cursor_type) + { + case HOLLOW_BOX_CURSOR: + if (row->visible_height >= STANDARD_BITMAP_HEIGHT (hollow_box_cursor_bits)) + cursor = HOLLOW_BOX_CURSOR_BITMAP; + else + cursor = HOLLOW_SQUARE_BITMAP; + break; + case FILLED_BOX_CURSOR: + cursor = FILLED_BOX_CURSOR_BITMAP; + break; + case BAR_CURSOR: + cursor = BAR_CURSOR_BITMAP; + break; + case HBAR_CURSOR: + cursor = HBAR_CURSOR_BITMAP; + break; + case NO_CURSOR: + default: + w->phys_cursor_on_p = 0; + row->cursor_in_fringe_p = 0; + break; + } + if (cursor != NO_FRINGE_BITMAP) + { + draw_fringe_bitmap_1 (w, row, 0, 2, cursor); + overlay = cursor == FILLED_BOX_CURSOR_BITMAP ? 3 : 1; + } + } + + draw_fringe_bitmap_1 (w, row, left_p, overlay, NO_FRINGE_BITMAP); + + if (left_p && row->overlay_arrow_p) + draw_fringe_bitmap_1 (w, row, 1, 1, + (w->overlay_arrow_bitmap + ? w->overlay_arrow_bitmap + : OVERLAY_ARROW_BITMAP)); +} + + +/* Draw fringe bitmaps for glyph row ROW on window W. Call this + function with input blocked. */ + +void +draw_row_fringe_bitmaps (w, row) + struct window *w; + struct glyph_row *row; +{ + xassert (interrupt_input_blocked); + + /* If row is completely invisible, because of vscrolling, we + don't have to draw anything. */ + if (row->visible_height <= 0) + return; + + if (WINDOW_LEFT_FRINGE_WIDTH (w) != 0) + draw_fringe_bitmap (w, row, 1); + + if (WINDOW_RIGHT_FRINGE_WIDTH (w) != 0) + draw_fringe_bitmap (w, row, 0); +} + +/* Draw the fringes of window W. Only fringes for rows marked for + update in redraw_fringe_bitmaps_p are drawn. */ + +void +draw_window_fringes (w) + struct window *w; +{ + struct glyph_row *row; + int yb = window_text_bottom_y (w); + int nrows = w->current_matrix->nrows; + int y = 0, rn; + + if (w->pseudo_window_p) + return; + + for (y = 0, rn = 0, row = w->current_matrix->rows; + y < yb && rn < nrows; + y += row->height, ++row, ++rn) + { + if (!row->redraw_fringe_bitmaps_p) + continue; + draw_row_fringe_bitmaps (w, row); + row->redraw_fringe_bitmaps_p = 0; + } +} + + +/* Recalculate the bitmaps to show in the fringes of window W. + If FORCE_P is 0, only mark rows with modified bitmaps for update in + redraw_fringe_bitmaps_p; else mark all rows for update. */ + +int +update_window_fringes (w, force_p) + struct window *w; + int force_p; +{ + struct glyph_row *row, *cur = 0; + int yb = window_text_bottom_y (w); + int rn, nrows = w->current_matrix->nrows; + int y; + int redraw_p = 0; + Lisp_Object ind; + int boundary_pos = 0, arrow_pos = 0; + int empty_pos = 0; + + if (w->pseudo_window_p) + return 0; + + if (!MINI_WINDOW_P (w) + && (ind = XBUFFER (w->buffer)->indicate_buffer_boundaries, !NILP (ind))) + { + int do_eob = 1, do_bob = 1; + Lisp_Object arrows; + + if (CONSP (ind)) + arrows = XCDR (ind), ind = XCAR (ind); + else + arrows = ind; + + if (EQ (ind, Qleft)) + boundary_pos = -1; + else if (EQ (ind, Qright)) + boundary_pos = 1; + + if (EQ (arrows, Qleft)) + arrow_pos = -1; + else if (EQ (arrows, Qright)) + arrow_pos = 1; + + for (y = 0, rn = 0; + y < yb && rn < nrows; + y += row->height, ++rn) + { + unsigned indicate_bob_p, indicate_top_line_p; + unsigned indicate_eob_p, indicate_bottom_line_p; + + row = w->desired_matrix->rows + rn; + if (!row->enabled_p) + row = w->current_matrix->rows + rn; + + indicate_bob_p = row->indicate_bob_p; + indicate_top_line_p = row->indicate_top_line_p; + indicate_eob_p = row->indicate_eob_p; + indicate_bottom_line_p = row->indicate_bottom_line_p; + + row->indicate_bob_p = row->indicate_top_line_p = 0; + row->indicate_eob_p = row->indicate_bottom_line_p = 0; + + if (!NILP (ind) + && MATRIX_ROW_START_CHARPOS (row) <= BUF_BEGV (XBUFFER (w->buffer))) + row->indicate_bob_p = do_bob, do_bob = 0; + else if (!NILP (arrows) + && (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0) == rn) + row->indicate_top_line_p = 1; + + if (!NILP (ind) + && MATRIX_ROW_END_CHARPOS (row) >= BUF_ZV (XBUFFER (w->buffer))) + row->indicate_eob_p = do_eob, do_eob = 0; + else if (!NILP (arrows) + && y + row->height >= yb) + row->indicate_bottom_line_p = 1; + + if (indicate_bob_p != row->indicate_bob_p + || indicate_top_line_p != row->indicate_top_line_p + || indicate_eob_p != row->indicate_eob_p + || indicate_bottom_line_p != row->indicate_bottom_line_p) + row->redraw_fringe_bitmaps_p = 1; + } + } + + if (EQ (XBUFFER (w->buffer)->indicate_empty_lines, Qright)) + empty_pos = 1; + else if (EQ (XBUFFER (w->buffer)->indicate_empty_lines, Qleft)) + empty_pos = -1; + + for (y = 0, rn = 0; + y < yb && rn < nrows; + y += row->height, rn++) + { + enum fringe_bitmap_type left, right; + unsigned left_face_id, right_face_id; + + row = w->desired_matrix->rows + rn; + cur = w->current_matrix->rows + rn; + if (!row->enabled_p) + row = cur; + + left_face_id = right_face_id = DEFAULT_FACE_ID; + + /* Decide which bitmap to draw in the left fringe. */ + if (WINDOW_LEFT_FRINGE_WIDTH (w) == 0) + left = NO_FRINGE_BITMAP; + else if (row->left_user_fringe_bitmap != NO_FRINGE_BITMAP) + { + left = row->left_user_fringe_bitmap; + left_face_id = row->left_user_fringe_face_id; + } + else if (row->indicate_bob_p && boundary_pos <= 0) + left = ((row->indicate_eob_p && boundary_pos < 0) + ? LEFT_BRACKET_BITMAP : TOP_LEFT_ANGLE_BITMAP); + else if (row->indicate_eob_p && boundary_pos < 0) + left = BOTTOM_LEFT_ANGLE_BITMAP; + else if (row->truncated_on_left_p) + left = LEFT_TRUNCATION_BITMAP; + else if (MATRIX_ROW_CONTINUATION_LINE_P (row)) + left = CONTINUATION_LINE_BITMAP; + else if (row->indicate_empty_line_p && empty_pos <= 0) + left = ZV_LINE_BITMAP; + else if (row->indicate_top_line_p && arrow_pos <= 0) + left = UP_ARROW_BITMAP; + else if (row->indicate_bottom_line_p && arrow_pos < 0) + left = DOWN_ARROW_BITMAP; + else + left = NO_FRINGE_BITMAP; + + /* Decide which bitmap to draw in the right fringe. */ + if (WINDOW_RIGHT_FRINGE_WIDTH (w) == 0) + right = NO_FRINGE_BITMAP; + else if (row->right_user_fringe_bitmap != NO_FRINGE_BITMAP) + { + right = row->right_user_fringe_bitmap; + right_face_id = row->right_user_fringe_face_id; + } + else if (row->indicate_bob_p && boundary_pos > 0) + right = ((row->indicate_eob_p && boundary_pos >= 0) + ? RIGHT_BRACKET_BITMAP : TOP_RIGHT_ANGLE_BITMAP); + else if (row->indicate_eob_p && boundary_pos >= 0) + right = BOTTOM_RIGHT_ANGLE_BITMAP; + else if (row->truncated_on_right_p) + right = RIGHT_TRUNCATION_BITMAP; + else if (row->continued_p) + right = CONTINUED_LINE_BITMAP; + else if (row->indicate_top_line_p && arrow_pos > 0) + right = UP_ARROW_BITMAP; + else if (row->indicate_bottom_line_p && arrow_pos >= 0) + right = DOWN_ARROW_BITMAP; + else if (row->indicate_empty_line_p + && (empty_pos > 0 + || (WINDOW_LEFT_FRINGE_WIDTH (w) == 0 && empty_pos == 0))) + right = ZV_LINE_BITMAP; + else + right = NO_FRINGE_BITMAP; + + if (force_p + || row->y != cur->y + || row->visible_height != cur->visible_height + || left != cur->left_fringe_bitmap + || right != cur->right_fringe_bitmap + || left_face_id != cur->left_fringe_face_id + || right_face_id != cur->right_fringe_face_id + || cur->redraw_fringe_bitmaps_p) + { + redraw_p = row->redraw_fringe_bitmaps_p = cur->redraw_fringe_bitmaps_p = 1; + cur->left_fringe_bitmap = left; + cur->right_fringe_bitmap = right; + cur->left_fringe_face_id = left_face_id; + cur->right_fringe_face_id = right_face_id; + } + + if (row->overlay_arrow_p != cur->overlay_arrow_p) + { + redraw_p = row->redraw_fringe_bitmaps_p = cur->redraw_fringe_bitmaps_p = 1; + cur->overlay_arrow_p = row->overlay_arrow_p; + } + + row->left_fringe_bitmap = left; + row->right_fringe_bitmap = right; + row->left_fringe_face_id = left_face_id; + row->right_fringe_face_id = right_face_id; + } + + return redraw_p; +} + + +/* Compute actual fringe widths for frame F. + + If REDRAW is 1, redraw F if the fringe settings was actually + modified and F is visible. + + Since the combined left and right fringe must occupy an integral + number of columns, we may need to add some pixels to each fringe. + Typically, we add an equal amount (+/- 1 pixel) to each fringe, + but a negative width value is taken literally (after negating it). + + We never make the fringes narrower than specified. It is planned + to make fringe bitmaps customizable and expandable, and at that + time, the user will typically specify the minimum number of pixels + needed for his bitmaps, so we shouldn't select anything less than + what is specified. +*/ + +void +compute_fringe_widths (f, redraw) + struct frame *f; + int redraw; +{ + int o_left = FRAME_LEFT_FRINGE_WIDTH (f); + int o_right = FRAME_RIGHT_FRINGE_WIDTH (f); + int o_cols = FRAME_FRINGE_COLS (f); + + Lisp_Object left_fringe = Fassq (Qleft_fringe, f->param_alist); + Lisp_Object right_fringe = Fassq (Qright_fringe, f->param_alist); + int left_fringe_width, right_fringe_width; + + if (!NILP (left_fringe)) + left_fringe = Fcdr (left_fringe); + if (!NILP (right_fringe)) + right_fringe = Fcdr (right_fringe); + + left_fringe_width = ((NILP (left_fringe) || !INTEGERP (left_fringe)) ? 8 : + XINT (left_fringe)); + right_fringe_width = ((NILP (right_fringe) || !INTEGERP (right_fringe)) ? 8 : + XINT (right_fringe)); + + if (left_fringe_width || right_fringe_width) + { + int left_wid = left_fringe_width >= 0 ? left_fringe_width : -left_fringe_width; + int right_wid = right_fringe_width >= 0 ? right_fringe_width : -right_fringe_width; + int conf_wid = left_wid + right_wid; + int font_wid = FRAME_COLUMN_WIDTH (f); + int cols = (left_wid + right_wid + font_wid-1) / font_wid; + int real_wid = cols * font_wid; + if (left_wid && right_wid) + { + if (left_fringe_width < 0) + { + /* Left fringe width is fixed, adjust right fringe if necessary */ + FRAME_LEFT_FRINGE_WIDTH (f) = left_wid; + FRAME_RIGHT_FRINGE_WIDTH (f) = real_wid - left_wid; + } + else if (right_fringe_width < 0) + { + /* Right fringe width is fixed, adjust left fringe if necessary */ + FRAME_LEFT_FRINGE_WIDTH (f) = real_wid - right_wid; + FRAME_RIGHT_FRINGE_WIDTH (f) = right_wid; + } + else + { + /* Adjust both fringes with an equal amount. + Note that we are doing integer arithmetic here, so don't + lose a pixel if the total width is an odd number. */ + int fill = real_wid - conf_wid; + FRAME_LEFT_FRINGE_WIDTH (f) = left_wid + fill/2; + FRAME_RIGHT_FRINGE_WIDTH (f) = right_wid + fill - fill/2; + } + } + else if (left_fringe_width) + { + FRAME_LEFT_FRINGE_WIDTH (f) = real_wid; + FRAME_RIGHT_FRINGE_WIDTH (f) = 0; + } + else + { + FRAME_LEFT_FRINGE_WIDTH (f) = 0; + FRAME_RIGHT_FRINGE_WIDTH (f) = real_wid; + } + FRAME_FRINGE_COLS (f) = cols; + } + else + { + FRAME_LEFT_FRINGE_WIDTH (f) = 0; + FRAME_RIGHT_FRINGE_WIDTH (f) = 0; + FRAME_FRINGE_COLS (f) = 0; + } + + if (redraw && FRAME_VISIBLE_P (f)) + if (o_left != FRAME_LEFT_FRINGE_WIDTH (f) || + o_right != FRAME_RIGHT_FRINGE_WIDTH (f) || + o_cols != FRAME_FRINGE_COLS (f)) + redraw_frame (f); +} + +DEFUN ("destroy-fringe-bitmap", Fdestroy_fringe_bitmap, Sdestroy_fringe_bitmap, + 1, 1, 0, + doc: /* Destroy fringe bitmap WHICH. +If WHICH overrides a standard fringe bitmap, the original bitmap is restored. */) + (which) + Lisp_Object which; +{ + int n; + struct fringe_bitmap **fbp; + + CHECK_NUMBER (which); + if (n = XINT (which), n >= max_used_fringe_bitmap) + return Qnil; + + fringe_faces[n] = FRINGE_FACE_ID; + + fbp = &fringe_bitmaps[n]; + if (*fbp && (*fbp)->dynamic) + { + if (rif->destroy_fringe_bitmap) + rif->destroy_fringe_bitmap (n); + xfree (*fbp); + *fbp = NULL; + } + + while (max_used_fringe_bitmap > MAX_STANDARD_FRINGE_BITMAPS + && fringe_bitmaps[max_used_fringe_bitmap - 1] == NULL) + max_used_fringe_bitmap--; + + return Qnil; +} + + +/* Initialize bitmap bit. + + On X, we bit-swap the built-in bitmaps and reduce bitmap + from short to char array if width is <= 8 bits. + + On MAC with big-endian CPU, we need to byte-swap each short. + + On W32 and MAC (little endian), there's no need to do this. +*/ + +void +init_fringe_bitmap (which, fb, once_p) + enum fringe_bitmap_type which; + struct fringe_bitmap *fb; + int once_p; +{ + if (once_p || fb->dynamic) + { +#if defined (HAVE_X_WINDOWS) + static unsigned char swap_nibble[16] + = { 0x0, 0x8, 0x4, 0xc, /* 0000 1000 0100 1100 */ + 0x2, 0xa, 0x6, 0xe, /* 0010 1010 0110 1110 */ + 0x1, 0x9, 0x5, 0xd, /* 0001 1001 0101 1101 */ + 0x3, 0xb, 0x7, 0xf }; /* 0011 1011 0111 1111 */ + unsigned short *bits = fb->bits; + int j; + + if (fb->width <= 8) + { + unsigned char *cbits = (unsigned char *)fb->bits; + for (j = 0; j < fb->height; j++) + { + unsigned short b = *bits++; + unsigned char c; + c = (unsigned char)((swap_nibble[b & 0xf] << 4) + | (swap_nibble[(b>>4) & 0xf])); + *cbits++ = (c >> (8 - fb->width)); + } + } + else + { + for (j = 0; j < fb->height; j++) + { + unsigned short b = *bits; + b = (unsigned short)((swap_nibble[b & 0xf] << 12) + | (swap_nibble[(b>>4) & 0xf] << 8) + | (swap_nibble[(b>>8) & 0xf] << 4) + | (swap_nibble[(b>>12) & 0xf])); + *bits++ = (b >> (16 - fb->width)); + } + } +#endif /* HAVE_X_WINDOWS */ + +#if defined (MAC_OS) && defined (WORDS_BIG_ENDIAN) + unsigned short *bits = fb->bits; + int j; + for (j = 0; j < fb->height; j++) + { + unsigned short b = *bits; + *bits++ = ((b >> 8) & 0xff) | ((b & 0xff) << 8); + } +#endif /* MAC_OS && WORDS_BIG_ENDIAN */ + } + + if (!once_p) + { + Fdestroy_fringe_bitmap (make_number (which)); + + if (rif->define_fringe_bitmap) + rif->define_fringe_bitmap (which, fb->bits, fb->height, fb->width); + + fringe_bitmaps[which] = fb; + if (which >= max_used_fringe_bitmap) + max_used_fringe_bitmap = which + 1; + } +} + + +DEFUN ("define-fringe-bitmap", Fdefine_fringe_bitmap, Sdefine_fringe_bitmap, + 1, 5, 0, + doc: /* Define a fringe bitmap from BITS of height HEIGHT and width WIDTH. +BITS is either a string or a vector of integers. +HEIGHT is height of bitmap. If HEIGHT is nil, use length of BITS. +WIDTH must be an integer between 1 and 16, or nil which defaults to 8. +Optional fourth arg ALIGN may be one of `top', `center', or `bottom', +indicating the positioning of the bitmap relative to the rows where it +is used; the default is to center the bitmap. Fourth arg may also be a +list (ALIGN PERIODIC) where PERIODIC non-nil specifies that the bitmap +should be repeated. +Optional fifth argument WHICH is bitmap number to redefine. +Return new bitmap number, or nil of no more free bitmap slots. */) + (bits, height, width, align, which) + Lisp_Object bits, height, width, align, which; +{ + Lisp_Object len; + int n, h, i, j; + unsigned short *b; + struct fringe_bitmap fb, *xfb; + int fill1 = 0, fill2 = 0; + + if (!STRINGP (bits) && !VECTORP (bits)) + bits = wrong_type_argument (Qstringp, bits); + + len = Flength (bits); + + if (NILP (height)) + h = fb.height = XINT (len); + else + { + CHECK_NUMBER (height); + fb.height = min (XINT (height), 255); + if (fb.height > XINT (len)) + { + h = XINT (len); + fill1 = (fb.height - h) / 2; + fill2 = fb.height - h - fill1; + } + } + + if (NILP (width)) + fb.width = 8; + else + { + CHECK_NUMBER (width); + fb.width = min (XINT (width), 255); + } + + fb.period = 0; + fb.align = ALIGN_BITMAP_CENTER; + + if (CONSP (align)) + { + Lisp_Object period = XCDR (align); + if (CONSP (period)) + { + period = XCAR (period); + if (!NILP (period)) + { + fb.period = fb.height; + fb.height = 255; + } + } + align = XCAR (align); + } + if (EQ (align, Qtop)) + fb.align = ALIGN_BITMAP_TOP; + else if (EQ (align, Qbottom)) + fb.align = ALIGN_BITMAP_BOTTOM; + else if (!NILP (align) && !EQ (align, Qcenter)) + error ("Bad align argument"); + + if (NILP (which)) + { + if (max_used_fringe_bitmap < MAX_FRINGE_BITMAPS) + n = max_used_fringe_bitmap++; + else + { + for (n = MAX_STANDARD_FRINGE_BITMAPS; + n < MAX_FRINGE_BITMAPS; + n++) + if (fringe_bitmaps[n] == NULL) + break; + if (n == MAX_FRINGE_BITMAPS) + return Qnil; + } + which = make_number (n); + } + else + { + CHECK_NUMBER (which); + n = XINT (which); + if (n <= NO_FRINGE_BITMAP || n >= MAX_FRINGE_BITMAPS) + error ("Invalid fringe bitmap number"); + } + + fb.dynamic = 1; + + xfb = (struct fringe_bitmap *) xmalloc (sizeof fb + + fb.height * BYTES_PER_BITMAP_ROW); + fb.bits = b = (unsigned short *) (xfb + 1); + bzero (b, fb.height); + + j = 0; + while (j < fb.height) + { + for (i = 0; i < fill1 && j < fb.height; i++) + b[j++] = 0; + for (i = 0; i < h && j < fb.height; i++) + { + Lisp_Object elt = Faref (bits, make_number (i)); + b[j++] = NUMBERP (elt) ? XINT (elt) : 0; + } + for (i = 0; i < fill2 && j < fb.height; i++) + b[j++] = 0; + } + + *xfb = fb; + + init_fringe_bitmap (n, xfb, 0); + + return which; +} + +DEFUN ("set-fringe-bitmap-face", Fset_fringe_bitmap_face, Sset_fringe_bitmap_face, + 1, 2, 0, + doc: /* Set face for fringe bitmap FRINGE-ID to FACE. +If FACE is nil, reset face to default fringe face. */) + (fringe_id, face) + Lisp_Object fringe_id, face; +{ + int face_id; + + CHECK_NUMBER (fringe_id); + if (!valid_fringe_bitmap_id_p (XINT (fringe_id))) + error ("Invalid fringe id"); + + if (!NILP (face)) + { + face_id = lookup_named_face (SELECTED_FRAME (), face); + if (face_id < 0) + error ("No such face"); + } + else + face_id = FRINGE_FACE_ID; + + fringe_faces [XINT (fringe_id)] = face_id; + + return Qnil; +} + +DEFUN ("fringe-bitmaps-at-pos", Ffringe_bitmaps_at_pos, Sfringe_bitmaps_at_pos, + 0, 2, 0, + doc: /* Return fringe bitmaps of row containing position POS in window WINDOW. +If WINDOW is nil, use selected window. If POS is nil, use value of point +in that window. Return value is a cons (LEFT . RIGHT) where LEFT and RIGHT +are the fringe bitmap numbers for the bitmaps in the left and right fringe, +resp. Return nil if POS is not visible in WINDOW. */) + (pos, window) + Lisp_Object pos, window; +{ + struct window *w; + struct buffer *old_buffer = NULL; + struct glyph_row *row; + int textpos; + + if (NILP (window)) + window = selected_window; + CHECK_WINDOW (window); + w = XWINDOW (window); + + if (!NILP (pos)) + { + CHECK_NUMBER_COERCE_MARKER (pos); + textpos = XINT (pos); + } + else if (w == XWINDOW (selected_window)) + textpos = PT; + else + textpos = XMARKER (w->pointm)->charpos; + + row = MATRIX_FIRST_TEXT_ROW (w->current_matrix); + row = row_containing_pos (w, textpos, row, NULL, 0); + if (row) + return Fcons (make_number (row->left_fringe_bitmap), + make_number (row->right_fringe_bitmap)); + else + return Qnil; +} + + +/*********************************************************************** + Initialization + ***********************************************************************/ + +void +syms_of_fringe () +{ + + defsubr (&Sdestroy_fringe_bitmap); + defsubr (&Sdefine_fringe_bitmap); + defsubr (&Sfringe_bitmaps_at_pos); + defsubr (&Sset_fringe_bitmap_face); + + DEFVAR_LISP ("overflow-newline-into-fringe", &Voverflow_newline_into_fringe, + doc: /* *Non-nil means that newline may flow into the right fringe. +This means that display lines which are exactly as wide as the window +(not counting the final newline) will only occupy one screen line, by +showing (or hiding) the final newline in the right fringe; when point +is at the final newline, the cursor is shown in the right fringe. +If nil, also continue lines which are exactly as wide as the window. */); + Voverflow_newline_into_fringe = Qt; + +} + +/* Initialize this module when Emacs starts. */ + +void +init_fringe_once () +{ + enum fringe_bitmap_type bt; + + for (bt = NO_FRINGE_BITMAP + 1; bt < MAX_STANDARD_FRINGE_BITMAPS; bt++) + init_fringe_bitmap(bt, &standard_bitmaps[bt], 1); +} + +void +init_fringe () +{ + int i; + + bzero (fringe_bitmaps, sizeof fringe_bitmaps); + for (i = 0; i < MAX_FRINGE_BITMAPS; i++) + fringe_faces[i] = FRINGE_FACE_ID; +} + +#ifdef HAVE_NTGUI + +void +w32_init_fringe () +{ + enum fringe_bitmap_type bt; + + for (bt = NO_FRINGE_BITMAP + 1; bt < MAX_STANDARD_FRINGE_BITMAPS; bt++) + { + struct fringe_bitmap *fb = &standard_bitmaps[bt]; + rif->define_fringe_bitmap (bt, fb->bits, fb->height, fb->width); + } +} + +void +w32_reset_fringes () +{ + /* Destroy row bitmaps. */ + int bt; + + for (bt = NO_FRINGE_BITMAP + 1; bt < max_used_fringe_bitmap; bt++) + rif->destroy_fringe_bitmap (bt); +} + +#endif /* HAVE_NTGUI */ + +#endif /* HAVE_WINDOW_SYSTEM */ + +/* arch-tag: 04596920-43eb-473d-b319-82712338162d + (do not change this comment) */ diff --git a/src/getloadavg.c b/src/getloadavg.c index 462ee16fa54..9a104cee7d8 100644 --- a/src/getloadavg.c +++ b/src/getloadavg.c @@ -1036,3 +1036,6 @@ main (argc, argv) exit (0); } #endif /* TEST */ + +/* arch-tag: 2b37a242-6289-41f4-8cd5-0e73fd615db1 + (do not change this comment) */ diff --git a/src/getpagesize.h b/src/getpagesize.h index 4d526183393..269a2ff17fd 100644 --- a/src/getpagesize.h +++ b/src/getpagesize.h @@ -57,3 +57,6 @@ Boston, MA 02111-1307, USA. */ # endif /* no _SC_PAGESIZE */ #endif /* no HAVE_GETPAGESIZE */ + +/* arch-tag: ff6206e3-97e2-4763-923a-e84bf28eabbc + (do not change this comment) */ diff --git a/src/gmalloc.c b/src/gmalloc.c index 7c654e1ece1..eae83a74eb6 100644 --- a/src/gmalloc.c +++ b/src/gmalloc.c @@ -352,6 +352,10 @@ Cambridge, MA 02139, USA. #include <errno.h> /* How to really get more memory. */ +#if defined(CYGWIN) +extern __ptr_t bss_sbrk PP ((ptrdiff_t __size)); +extern int bss_sbrk_did_unexec; +#endif __ptr_t (*__morecore) PP ((ptrdiff_t __size)) = __default_morecore; /* Debugging hook for `malloc'. */ @@ -1572,7 +1576,14 @@ __ptr_t __default_morecore (increment) __malloc_ptrdiff_t increment; { - __ptr_t result = (__ptr_t) __sbrk (increment); + __ptr_t result; +#if defined(CYGWIN) + if (!bss_sbrk_did_unexec) + { + return bss_sbrk (increment); + } +#endif + result = (__ptr_t) __sbrk (increment); if (result == (__ptr_t) -1) return NULL; return result; @@ -1978,3 +1989,6 @@ mprobe (__ptr_t ptr) } #endif /* GC_MCHECK */ + +/* arch-tag: 93dce5c0-f49a-41b5-86b1-f91c4169c02e + (do not change this comment) */ diff --git a/src/gnu.h b/src/gnu.h index b5cf7261f7d..1d623431af8 100644 --- a/src/gnu.h +++ b/src/gnu.h @@ -31,3 +31,6 @@ static unsigned char gnu_bits[] = { 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +/* arch-tag: b57020c7-c937-4d77-8ca6-3875178d9828 + (do not change this comment) */ diff --git a/src/gtkutil.c b/src/gtkutil.c index 1f92040ff69..4d0b50573f7 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -36,9 +36,128 @@ Boston, MA 02111-1307, USA. */ #include "coding.h" #include <gdk/gdkkeysyms.h> + #define FRAME_TOTAL_PIXEL_HEIGHT(f) \ (FRAME_PIXEL_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f)) + +/*********************************************************************** + Display handling functions + ***********************************************************************/ + +#ifdef HAVE_GTK_MULTIDISPLAY + +/* Return the GdkDisplay that corresponds to the X display DPY. */ +static GdkDisplay * +xg_get_gdk_display (dpy) + Display *dpy; +{ + return gdk_x11_lookup_xdisplay (dpy); +} + +/* When the GTK widget W is to be created on a display for F that + is not the default display, set the display for W. + W can be a GtkMenu or a GtkWindow widget. */ +static void +xg_set_screen (w, f) + GtkWidget *w; + FRAME_PTR f; +{ + if (FRAME_X_DISPLAY (f) != GDK_DISPLAY ()) + { + GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f)); + GdkScreen *gscreen = gdk_display_get_default_screen (gdpy); + + if (GTK_IS_MENU (w)) + gtk_menu_set_screen (GTK_MENU (w), gscreen); + else + gtk_window_set_screen (GTK_WINDOW (w), gscreen); + } +} + + +#else /* not HAVE_GTK_MULTIDISPLAY */ + +/* Make some defines so we can use the GTK 2.2 functions when + compiling with GTK 2.0. */ +#define xg_set_screen(w, f) +#define gdk_xid_table_lookup_for_display(dpy, w) gdk_xid_table_lookup (w) +#define gdk_pixmap_foreign_new_for_display(dpy, p) gdk_pixmap_foreign_new (p) +#define gdk_cursor_new_for_display(dpy, c) gdk_cursor_new (c) +#define gdk_x11_lookup_xdisplay(dpy) 0 +#define GdkDisplay void + +#endif /* not HAVE_GTK_MULTIDISPLAY */ + +/* Open a display named by DISPLAY_NAME. The display is returned in *DPY. + *DPY is set to NULL if the display can't be opened. + + Returns non-zero if display could be opened, zero if display could not + be opened, and less than zero if the GTK version doesn't support + multipe displays. */ +int +xg_display_open (display_name, dpy) + char *display_name; + Display **dpy; +{ +#ifdef HAVE_GTK_MULTIDISPLAY + GdkDisplay *gdpy; + + gdpy = gdk_display_open (display_name); + *dpy = gdpy ? GDK_DISPLAY_XDISPLAY (gdpy) : NULL; + + return gdpy != NULL; + +#else /* not HAVE_GTK_MULTIDISPLAY */ + + return -1; +#endif /* not HAVE_GTK_MULTIDISPLAY */ +} + + +void +xg_display_close (Display *dpy) +{ +#ifdef HAVE_GTK_MULTIDISPLAY + GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy); + + /* GTK 2.2 has a bug that makes gdk_display_close crash (bug + http://bugzilla.gnome.org/show_bug.cgi?id=85715). This way + we can continue running, but there will be memory leaks. */ + +#if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 4 + + /* If this is the default display, we must change it before calling + dispose, otherwise it will crash. */ + if (gdk_display_get_default () == gdpy) + { + struct x_display_info *dpyinfo; + Display *new_dpy = 0; + GdkDisplay *gdpy_new; + + /* Find another display. */ + for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) + if (dpyinfo->display != dpy) + { + new_dpy = dpyinfo->display; + break; + } + + if (! new_dpy) return; /* Emacs will exit anyway. */ + + gdpy_new = gdk_x11_lookup_xdisplay (new_dpy); + gdk_display_manager_set_default_display (gdk_display_manager_get (), + gdpy_new); + } + + g_object_run_dispose (G_OBJECT (gdpy)); + +#else + /* I hope this will be fixed in GTK 2.4. It is what bug 85715 says. */ + gdk_display_close (gdpy); +#endif +#endif /* HAVE_GTK_MULTIDISPLAY */ +} /*********************************************************************** @@ -48,10 +167,6 @@ Boston, MA 02111-1307, USA. */ NULL if no timer is started. */ static struct atimer *xg_timer; -/* The cursor used for scroll bars and popup menus. - We only have one cursor for all scroll bars and all popup menus. */ -static GdkCursor *xg_left_ptr_cursor; - /* The next two variables and functions are taken from lwlib. */ static widget_value *widget_value_free_list; @@ -103,24 +218,48 @@ free_widget_value (wv) } } -/* Set *CURSOR on W and all widgets W contain. We must do like this - for scroll bars and menu because they create widgets internally, - and it is those widgets that are visible. - If *CURSOR is NULL, create a GDK_LEFT_PTR cursor and set *CURSOR to - the created cursor. */ -void +/* Create and return the cursor to be used for popup menus and + scroll bars on display DPY. */ +GdkCursor * +xg_create_default_cursor (dpy) + Display *dpy; +{ + GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy); + return gdk_cursor_new_for_display (gdpy, GDK_LEFT_PTR); +} + +/* For the image defined in IMG, make and return a GdkPixmap for + the pixmap in *GPIX, and a GdkBitmap for the mask in *GMASK. + If IMG has no mask, *GMASK is set to NULL. + The image is defined on the display where frame F is. */ +static void +xg_get_gdk_pixmap_and_mask (f, img, gpix, gmask) + FRAME_PTR f; + struct image *img; + GdkPixmap **gpix; + GdkBitmap **gmask; +{ + GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (FRAME_X_DISPLAY (f)); + + *gpix = gdk_pixmap_foreign_new_for_display (gdpy, img->pixmap); + *gmask = img->mask ? + (GdkBitmap*) gdk_pixmap_foreign_new_for_display (gdpy, img->mask) + : 0; +} + + +/* Set CURSOR on W and all widgets W contain. We must do like this + for scroll bars and menu because they create widgets internally, + and it is those widgets that are visible. */ +static void xg_set_cursor (w, cursor) GtkWidget *w; - GdkCursor **cursor; + GdkCursor *cursor; { GList *children = gdk_window_peek_children (w->window); - /* Create the cursor unless already created. */ - if (! *cursor) - *cursor = gdk_cursor_new (GDK_LEFT_PTR); - - gdk_window_set_cursor (w->window, *cursor); + gdk_window_set_cursor (w->window, cursor); /* The scroll bar widget has more than one GDK window (had to look at the source to figure this out), and there is no way to set cursor @@ -128,7 +267,7 @@ xg_set_cursor (w, cursor) Ditto for menus. */ for ( ; children; children = g_list_next (children)) - gdk_window_set_cursor (GDK_WINDOW (children->data), *cursor); + gdk_window_set_cursor (GDK_WINDOW (children->data), cursor); } /* Timer function called when a timeout occurs for xg_timer. @@ -376,25 +515,28 @@ xg_frame_set_char_size (f, cols, rows) gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), pixelwidth, pixelheight); xg_resize_widgets (f, pixelwidth, pixelheight); - + x_wm_set_size_hint (f, 0, 0); SET_FRAME_GARBAGED (f); cancel_mouse_face (f); } -/* Convert an X Window WSESC to its corresponding GtkWidget. +/* Convert an X Window WSESC on display DPY to its corresponding GtkWidget. Must be done like this, because GtkWidget:s can have "hidden" X Window that aren't accessible. Return 0 if no widget match WDESC. */ GtkWidget * -xg_win_to_widget (wdesc) +xg_win_to_widget (dpy, wdesc) + Display *dpy; Window wdesc; { gpointer gdkwin; GtkWidget *gwdesc = 0; BLOCK_INPUT; - gdkwin = gdk_xid_table_lookup (wdesc); + + gdkwin = gdk_xid_table_lookup_for_display (gdk_x11_lookup_xdisplay (dpy), + wdesc); if (gdkwin) { GdkEvent event; @@ -429,9 +571,9 @@ xg_pix_to_gcolor (w, pixel, c) Return TRUE to tell GTK that this expose event has been fully handeled and that GTK shall do nothing more with it. */ static gboolean -xg_fixed_handle_expose(GtkWidget *widget, - GdkEventExpose *event, - gpointer user_data) +xg_fixed_handle_expose (GtkWidget *widget, + GdkEventExpose *event, + gpointer user_data) { GList *iter; @@ -483,6 +625,8 @@ xg_create_frame_widgets (f) BLOCK_INPUT; wtop = gtk_window_new (GTK_WINDOW_TOPLEVEL); + xg_set_screen (wtop, f); + wvbox = gtk_vbox_new (FALSE, 0); wfixed = gtk_fixed_new (); /* Must have this to place scroll bars */ @@ -512,7 +656,8 @@ xg_create_frame_widgets (f) gtk_fixed_set_has_window (GTK_FIXED (wfixed), TRUE); - gtk_widget_set_size_request (wfixed, FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f)); + gtk_widget_set_size_request (wfixed, FRAME_PIXEL_WIDTH (f), + FRAME_PIXEL_HEIGHT (f)); gtk_container_add (GTK_CONTAINER (wtop), wvbox); gtk_box_pack_end (GTK_BOX (wvbox), wfixed, TRUE, TRUE, 0); @@ -963,6 +1108,8 @@ xg_get_file_name (f, prompt, default_filename, mustmatch_p) filewin = gtk_file_selection_new (prompt); filesel = GTK_FILE_SELECTION (filewin); + xg_set_screen (filewin, f); + gtk_widget_set_name (filewin, "emacs-filedialog"); gtk_window_set_transient_for (GTK_WINDOW (filewin), @@ -1333,27 +1480,29 @@ xg_separator_p (char *label) return 0; } -GtkWidget *xg_did_tearoff; +static int xg_detached_menus; + +/* Returns non-zero if there are detached menus. */ +int +xg_have_tear_offs () +{ + return xg_detached_menus > 0; +} /* Callback invoked when a detached menu window is removed. Here we - delete the popup menu. + decrease the xg_detached_menus count. WIDGET is the top level window that is removed (the parent of the menu). - EVENT is the event that triggers the window removal. - CLIENT_DATA points to the menu that is detached. - - Returns TRUE to tell GTK to stop processing this event. */ -static gboolean -tearoff_remove (widget, event, client_data) + CLIENT_DATA is not used. */ +static void +tearoff_remove (widget, client_data) GtkWidget *widget; - GdkEvent *event; gpointer client_data; { - gtk_widget_destroy (GTK_WIDGET (client_data)); - return TRUE; + if (xg_detached_menus > 0) --xg_detached_menus; } -/* Callback invoked when a menu is detached. It sets the xg_did_tearoff - variable. +/* Callback invoked when a menu is detached. It increases the + xg_detached_menus count. WIDGET is the GtkTearoffMenuItem. CLIENT_DATA is not used. */ static void @@ -1362,31 +1511,15 @@ tearoff_activate (widget, client_data) gpointer client_data; { GtkWidget *menu = gtk_widget_get_parent (widget); - if (! gtk_menu_get_tearoff_state (GTK_MENU (menu))) - return; - - xg_did_tearoff = menu; + if (gtk_menu_get_tearoff_state (GTK_MENU (menu))) + { + ++xg_detached_menus; + g_signal_connect (G_OBJECT (gtk_widget_get_toplevel (widget)), + "destroy", + G_CALLBACK (tearoff_remove), 0); + } } -/* If a detach of a popup menu is done, this function should be called - to keep the menu around until the detached window is removed. - MENU is the top level menu for the popup, - SUBMENU is the menu that got detached (that is MENU or a - submenu of MENU), see the xg_did_tearoff variable. */ -void -xg_keep_popup (menu, submenu) - GtkWidget *menu; - GtkWidget *submenu; -{ - GtkWidget *p; - - /* Find the top widget for the detached menu. */ - p = gtk_widget_get_toplevel (submenu); - - /* Delay destroying the menu until the detached menu is removed. */ - g_signal_connect (G_OBJECT (p), "unmap_event", - G_CALLBACK (tearoff_remove), menu); -} /* Create a menu item widget, and connect the callbacks. ITEM decribes the menu item. @@ -1514,7 +1647,11 @@ create_menus (data, f, select_cb, deactivate_cb, highlight_cb, if (! topmenu) { - if (! menu_bar_p) wmenu = gtk_menu_new (); + if (! menu_bar_p) + { + wmenu = gtk_menu_new (); + xg_set_screen (wmenu, f); + } else wmenu = gtk_menu_bar_new (); /* Put cl_data on the top menu for easier access. */ @@ -1585,7 +1722,7 @@ create_menus (data, f, select_cb, deactivate_cb, highlight_cb, highlight_cb, 0, 0, - 1, + add_tearoff_p, 0, cl_data, 0); @@ -1626,37 +1763,39 @@ xg_create_widget (type, name, f, val, GCallback highlight_cb; { GtkWidget *w = 0; + int menu_bar_p = strcmp (type, "menubar") == 0; + int pop_up_p = strcmp (type, "popup") == 0; + if (strcmp (type, "dialog") == 0) { w = create_dialog (val, select_cb, deactivate_cb); + xg_set_screen (w, f); gtk_window_set_transient_for (GTK_WINDOW (w), GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f))); gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE); - - if (w) - gtk_widget_set_name (w, "emacs-dialog"); + gtk_widget_set_name (w, "emacs-dialog"); } - else if (strcmp (type, "menubar") == 0 || strcmp (type, "popup") == 0) + else if (menu_bar_p || pop_up_p) { w = create_menus (val->contents, f, select_cb, deactivate_cb, highlight_cb, - strcmp (type, "popup") == 0, - strcmp (type, "menubar") == 0, - 1, + pop_up_p, + menu_bar_p, + menu_bar_p, 0, 0, name); /* Set the cursor to an arrow for popup menus when they are mapped. This is done by default for menu bar menus. */ - if (strcmp (type, "popup") == 0) + if (pop_up_p) { /* Must realize so the GdkWindow inside the widget is created. */ gtk_widget_realize (w); - xg_set_cursor (w, &xg_left_ptr_cursor); + xg_set_cursor (w, FRAME_X_DISPLAY_INFO (f)->xg_cursor); } } else @@ -1834,9 +1973,16 @@ xg_update_menubar (menubar, f, list, iter, pos, val, is up to date when leaving the minibuffer. */ GtkLabel *wlabel = GTK_LABEL (gtk_bin_get_child (GTK_BIN (witem))); char *utf8_label = get_utf8_string (val->name); + GtkWidget *submenu = gtk_menu_item_get_submenu (witem); gtk_label_set_text (wlabel, utf8_label); + /* If this item has a submenu that has been detached, change + the title in the WM decorations also. */ + if (submenu && gtk_menu_get_tearoff_state (GTK_MENU (submenu))) + /* Set the title of the detached window. */ + gtk_menu_set_title (GTK_MENU (submenu), utf8_label); + iter = g_list_next (iter); val = val->next; ++pos; @@ -2222,18 +2368,15 @@ xg_modify_menubar_widgets (menubar, f, val, deep_p, cl_data = (xg_menu_cb_data*) g_object_get_data (G_OBJECT (menubar), XG_FRAME_DATA); - if (! deep_p) - { - widget_value *cur = val->contents; - xg_update_menubar (menubar, f, &list, list, 0, cur, - select_cb, highlight_cb, cl_data); - } - else + xg_update_menubar (menubar, f, &list, list, 0, val->contents, + select_cb, highlight_cb, cl_data); + + if (deep_p); { widget_value *cur; /* Update all sub menus. - We must keep the submenu names (GTK menu item widgets) since the + We must keep the submenus (GTK menu item widgets) since the X Window in the XEvent that activates the menu are those widgets. */ /* Update cl_data, menu_item things in F may have changed. */ @@ -2268,8 +2411,10 @@ xg_modify_menubar_widgets (menubar, f, val, deep_p, a new menu bar item, it has no sub menu yet. So we set the newly created sub menu under witem. */ if (newsub != sub) - gtk_menu_item_set_submenu (witem, newsub); - + { + xg_set_screen (newsub, f); + gtk_menu_item_set_submenu (witem, newsub); + } } } @@ -2425,16 +2570,17 @@ xg_get_widget_from_map (idx) return 0; } -/* Return the scrollbar id for X Window WID. +/* Return the scrollbar id for X Window WID on display DPY. Return -1 if WID not in id_to_widget. */ int -xg_get_scroll_id_for_window (wid) +xg_get_scroll_id_for_window (dpy, wid) + Display *dpy; Window wid; { int idx; GtkWidget *w; - w = xg_win_to_widget (wid); + w = xg_win_to_widget (dpy, wid); if (w) { @@ -2541,7 +2687,7 @@ xg_create_scroll_bar (f, bar, scroll_callback, scroll_bar_name) wscroll, -1, -1); /* Set the cursor to an arrow. */ - xg_set_cursor (wscroll, &xg_left_ptr_cursor); + xg_set_cursor (wscroll, FRAME_X_DISPLAY_INFO (f)->xg_cursor); SET_SCROLL_BAR_X_WINDOW (bar, scroll_id); } @@ -2960,8 +3106,8 @@ xg_tool_bar_item_expose_callback (w, event, client_data) event->area.x -= width > event->area.width ? width-event->area.width : 0; event->area.y -= height > event->area.height ? height-event->area.height : 0; - event->area.x = max(0, event->area.x); - event->area.y = max(0, event->area.y); + event->area.x = max (0, event->area.x); + event->area.y = max (0, event->area.y); event->area.width = max (width, event->area.width); event->area.height = max (height, event->area.height); @@ -2983,7 +3129,7 @@ xg_tool_bar_expose_callback (w, event, client_data) GdkEventExpose *event; gpointer client_data; { - update_frame_tool_bar((FRAME_PTR)client_data); + update_frame_tool_bar ((FRAME_PTR) client_data); return FALSE; } @@ -3116,11 +3262,12 @@ update_frame_tool_bar (f) if (! wicon) { - GdkPixmap *gpix = gdk_pixmap_foreign_new (img->pixmap); - GdkBitmap *gmask = img->mask ? - (GdkBitmap*) gdk_pixmap_foreign_new (img->mask) : 0; + GdkPixmap *gpix; + GdkBitmap *gmask; + GtkWidget *w; - GtkWidget *w = gtk_image_new_from_pixmap (gpix, gmask); + xg_get_gdk_pixmap_and_mask (f, img, &gpix, &gmask); + w = gtk_image_new_from_pixmap (gpix, gmask); gtk_toolbar_append_item (GTK_TOOLBAR (x->toolbar_widget), 0, 0, 0, w, @@ -3178,10 +3325,10 @@ update_frame_tool_bar (f) if (old_img != img->pixmap) { - GdkPixmap *gpix = gdk_pixmap_foreign_new (img->pixmap); - GdkBitmap *gmask = img->mask ? - (GdkBitmap*) gdk_pixmap_foreign_new (img->mask) : 0; + GdkPixmap *gpix; + GdkBitmap *gmask; + xg_get_gdk_pixmap_and_mask (f, img, &gpix, &gmask); gtk_image_set_from_pixmap (wimage, gpix, gmask); } @@ -3249,9 +3396,7 @@ void xg_initialize () { xg_ignore_gtk_scrollbar = 0; - xg_left_ptr_cursor = 0; - xg_did_tearoff = 0; - + xg_detached_menus = 0; xg_menu_cb_list.prev = xg_menu_cb_list.next = xg_menu_item_cb_list.prev = xg_menu_item_cb_list.next = 0; @@ -3275,3 +3420,6 @@ xg_initialize () } #endif /* USE_GTK */ + +/* arch-tag: fe7104da-bc1e-4aba-9bd1-f349c528f7e3 + (do not change this comment) */ diff --git a/src/gtkutil.h b/src/gtkutil.h index a53a3fd5bdc..b31ec8c2a1f 100644 --- a/src/gtkutil.h +++ b/src/gtkutil.h @@ -150,9 +150,9 @@ extern void xg_modify_menubar_widgets P_ ((GtkWidget *menubar, extern int xg_update_frame_menubar P_ ((FRAME_PTR f)); -extern void xg_keep_popup P_ ((GtkWidget *menu, GtkWidget *submenu)); +extern int xg_have_tear_offs P_ ((void)); -extern int xg_get_scroll_id_for_window P_ ((Window wid)); +extern int xg_get_scroll_id_for_window P_ ((Display *dpy, Window wid)); extern void xg_create_scroll_bar P_ ((FRAME_PTR f, struct scroll_bar *bar, @@ -184,7 +184,12 @@ extern void xg_resize_widgets P_ ((FRAME_PTR f, int pixelheight)); extern void xg_frame_cleared P_ ((FRAME_PTR f)); extern void xg_frame_set_char_size P_ ((FRAME_PTR f, int cols, int rows)); -extern GtkWidget * xg_win_to_widget P_ ((Window)); +extern GtkWidget * xg_win_to_widget P_ ((Display *dpy, Window wdesc)); + +extern int xg_display_open P_ ((char *display_name, Display **dpy)); +extern void xg_display_close P_ ((Display *dpy)); +extern GdkCursor * xg_create_default_cursor P_ ((Display *dpy)); + extern int xg_create_frame_widgets P_ ((FRAME_PTR f)); extern void x_wm_set_size_hint P_ ((FRAME_PTR f, long flags, @@ -201,11 +206,8 @@ extern void xg_initialize P_ ((void)); to indicate that the callback should do nothing. */ extern int xg_ignore_gtk_scrollbar; -/* If a detach of a menu is done, this is the menu widget that got - detached. Must be set to NULL before popping up popup menus. - Used with xg_keep_popup to delay deleting popup menus when they - have been detached. */ -extern GtkWidget *xg_did_tearoff; - #endif /* USE_GTK */ #endif /* GTKUTIL_H */ + +/* arch-tag: 0757f3dc-00c7-4cee-9e4c-282cf1d34c72 + (do not change this comment) */ diff --git a/src/hftctl.c b/src/hftctl.c index 272f7bad7fe..0609f840e20 100644 --- a/src/hftctl.c +++ b/src/hftctl.c @@ -337,3 +337,6 @@ WR_REQ (fd, request, cmdlen, cmd, resplen) return (0); } + +/* arch-tag: cfd4f3bd-fd49-44e6-9f69-c8abdf367650 + (do not change this comment) */ diff --git a/src/image.c b/src/image.c new file mode 100644 index 00000000000..34db5e53367 --- /dev/null +++ b/src/image.c @@ -0,0 +1,7532 @@ +/* Functions for image support on window system. + Copyright (C) 1989, 92, 93, 94, 95, 96, 97, 98, 99, 2000,01,02,03,04 + Free Software Foundation. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include <config.h> +#include <signal.h> +#include <stdio.h> +#include <math.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +/* This makes the fields of a Display accessible, in Xlib header files. */ + +#define XLIB_ILLEGAL_ACCESS + +#include "lisp.h" +#include "frame.h" +#include "window.h" +#include "dispextern.h" +#include "blockinput.h" +#include "systime.h" +#include <epaths.h> + + +#ifdef HAVE_X_WINDOWS +#include "xterm.h" +#include <sys/types.h> +#include <sys/stat.h> + +#define COLOR_TABLE_SUPPORT 1 + +typedef struct x_bitmap_record Bitmap_Record; +#define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y) +#define NO_PIXMAP None +#define PNG_BG_COLOR_SHIFT 0 + +#define RGB_PIXEL_COLOR unsigned long + +#define PIX_MASK_RETAIN(f) 0 +#define PIX_MASK_DRAW(f) 1 +#endif /* HAVE_X_WINDOWS */ + + +#ifdef HAVE_NTGUI +#include "w32term.h" + +/* W32_TODO : Color tables on W32. */ +#undef COLOR_TABLE_SUPPORT + +typedef struct w32_bitmap_record Bitmap_Record; +#define GET_PIXEL(ximg, x, y) GetPixel(ximg, x, y) +#define NO_PIXMAP 0 +#define PNG_BG_COLOR_SHIFT 0 + +#define RGB_PIXEL_COLOR COLORREF + +#define PIX_MASK_RETAIN(f) 0 +#define PIX_MASK_DRAW(f) 1 + +#define FRAME_X_VISUAL(f) FRAME_X_DISPLAY_INFO (f)->visual +#define x_defined_color w32_defined_color +#define DefaultDepthOfScreen(screen) (one_w32_display_info.n_cbits) +#endif /* HAVE_NTGUI */ + + +#ifdef MAC_OS +#include "macterm.h" +#ifndef MAC_OSX +#include <alloca.h> +#endif +#ifdef MAC_OSX +#include <sys/stat.h> +#include <QuickTime/QuickTime.h> +#else /* not MAC_OSX */ +#include <Windows.h> +#include <Gestalt.h> +#include <TextUtils.h> +#endif /* not MAC_OSX */ + +/* MAC_TODO : Color tables on Mac. */ +#undef COLOR_TABLE_SUPPORT + +#define ZPixmap 0 /* arbitrary */ +typedef struct mac_bitmap_record Bitmap_Record; + +#define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y) +#define NO_PIXMAP 0 +#define PNG_BG_COLOR_SHIFT 8 + +#define RGB_PIXEL_COLOR unsigned long + +#define FRAME_X_VISUAL(f) FRAME_X_DISPLAY_INFO (f)->visual +#define x_defined_color mac_defined_color +#define DefaultDepthOfScreen(screen) (one_mac_display_info.n_planes) +#define XDrawLine(display, w, gc, x1, y1, x2, y2) \ + mac_draw_line_to_pixmap(display, w, gc, x1, y1, x2, y2) + +#endif /* MAC_OS */ + + +/* Search path for bitmap files. */ + +Lisp_Object Vx_bitmap_file_path; + + +static void x_disable_image P_ ((struct frame *, struct image *)); +static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object, + Lisp_Object)); + +static void init_color_table P_ ((void)); +static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b)); +#ifdef COLOR_TABLE_SUPPORT +static void free_color_table P_ ((void)); +static unsigned long *colors_in_color_table P_ ((int *n)); +static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p)); +#endif + +/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap + id, which is just an int that this section returns. Bitmaps are + reference counted so they can be shared among frames. + + Bitmap indices are guaranteed to be > 0, so a negative number can + be used to indicate no bitmap. + + If you use x_create_bitmap_from_data, then you must keep track of + the bitmaps yourself. That is, creating a bitmap from the same + data more than once will not be caught. */ + +#ifdef MAC_OS + +static XImagePtr +XGetImage (display, pixmap, x, y, width, height, plane_mask, format) + Display *display; /* not used */ + Pixmap pixmap; + int x, y; /* not used */ + unsigned int width, height; /* not used */ + unsigned long plane_mask; /* not used */ + int format; /* not used */ +{ +#if GLYPH_DEBUG + xassert (x == 0 && y == 0); + { + Rect ri, rp; + SetRect (&ri, 0, 0, width, height); + xassert (EqualRect (&ri, GetPixBounds (GetGWorldPixMap (pixmap), &rp))); + } + xassert (! (pixelsLocked & GetPixelsState (GetGWorldPixMap (pixmap)))); +#endif + + LockPixels (GetGWorldPixMap (pixmap)); + + return pixmap; +} + +static void +XPutPixel (ximage, x, y, pixel) + XImagePtr ximage; + int x, y; + unsigned long pixel; +{ + RGBColor color; + + SetGWorld (ximage, NULL); + + color.red = RED16_FROM_ULONG (pixel); + color.green = GREEN16_FROM_ULONG (pixel); + color.blue = BLUE16_FROM_ULONG (pixel); + SetCPixel (x, y, &color); +} + +static unsigned long +XGetPixel (ximage, x, y) + XImagePtr ximage; + int x, y; +{ + RGBColor color; + + SetGWorld (ximage, NULL); + + GetCPixel (x, y, &color); + return RGB_TO_ULONG (color.red >> 8, color.green >> 8, color.blue >> 8); +} + +static void +XDestroyImage (ximg) + XImagePtr ximg; +{ + UnlockPixels (GetGWorldPixMap (ximg)); +} +#endif + + +/* Functions to access the contents of a bitmap, given an id. */ + +int +x_bitmap_height (f, id) + FRAME_PTR f; + int id; +{ + return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].height; +} + +int +x_bitmap_width (f, id) + FRAME_PTR f; + int id; +{ + return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].width; +} + +#if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI) +int +x_bitmap_pixmap (f, id) + FRAME_PTR f; + int id; +{ + return (int) FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap; +} +#endif + +#ifdef HAVE_X_WINDOWS +int +x_bitmap_mask (f, id) + FRAME_PTR f; + int id; +{ + return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].mask; +} +#endif + +/* Allocate a new bitmap record. Returns index of new record. */ + +static int +x_allocate_bitmap_record (f) + FRAME_PTR f; +{ + Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); + int i; + + if (dpyinfo->bitmaps == NULL) + { + dpyinfo->bitmaps_size = 10; + dpyinfo->bitmaps + = (Bitmap_Record *) xmalloc (dpyinfo->bitmaps_size * sizeof (Bitmap_Record)); + dpyinfo->bitmaps_last = 1; + return 1; + } + + if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size) + return ++dpyinfo->bitmaps_last; + + for (i = 0; i < dpyinfo->bitmaps_size; ++i) + if (dpyinfo->bitmaps[i].refcount == 0) + return i + 1; + + dpyinfo->bitmaps_size *= 2; + dpyinfo->bitmaps + = (Bitmap_Record *) xrealloc (dpyinfo->bitmaps, + dpyinfo->bitmaps_size * sizeof (Bitmap_Record)); + return ++dpyinfo->bitmaps_last; +} + +/* Add one reference to the reference count of the bitmap with id ID. */ + +void +x_reference_bitmap (f, id) + FRAME_PTR f; + int id; +{ + ++FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].refcount; +} + +/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */ + +int +x_create_bitmap_from_data (f, bits, width, height) + struct frame *f; + char *bits; + unsigned int width, height; +{ + Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); + int id; + +#ifdef HAVE_X_WINDOWS + Pixmap bitmap; + bitmap = XCreateBitmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + bits, width, height); + if (! bitmap) + return -1; +#endif /* HAVE_X_WINDOWS */ + +#ifdef HAVE_NTGUI + Pixmap bitmap; + bitmap = CreateBitmap (width, height, + FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_planes, + FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_cbits, + bits); + if (! bitmap) + return -1; +#endif /* HAVE_NTGUI */ + +#ifdef MAC_OS + /* MAC_TODO: for now fail if width is not mod 16 (toolbox requires it) */ + if (width % 16 != 0) + return -1; +#endif + + id = x_allocate_bitmap_record (f); +#ifdef MAC_OS + dpyinfo->bitmaps[id - 1].bitmap_data = (char *) xmalloc (height * width); + if (! dpyinfo->bitmaps[id - 1].bitmap_data) + return -1; + bcopy (bits, dpyinfo->bitmaps[id - 1].bitmap_data, height * width); +#endif /* MAC_OS */ + + dpyinfo->bitmaps[id - 1].file = NULL; + dpyinfo->bitmaps[id - 1].height = height; + dpyinfo->bitmaps[id - 1].width = width; + dpyinfo->bitmaps[id - 1].refcount = 1; + +#ifdef HAVE_X_WINDOWS + dpyinfo->bitmaps[id - 1].pixmap = bitmap; + dpyinfo->bitmaps[id - 1].have_mask = 0; + dpyinfo->bitmaps[id - 1].depth = 1; +#endif /* HAVE_X_WINDOWS */ + +#ifdef HAVE_NTGUI + dpyinfo->bitmaps[id - 1].pixmap = bitmap; + dpyinfo->bitmaps[id - 1].hinst = NULL; + dpyinfo->bitmaps[id - 1].depth = 1; +#endif /* HAVE_NTGUI */ + + return id; +} + +/* Create bitmap from file FILE for frame F. */ + +int +x_create_bitmap_from_file (f, file) + struct frame *f; + Lisp_Object file; +{ +#ifdef MAC_OS + return -1; /* MAC_TODO : bitmap support */ +#endif /* MAC_OS */ + +#ifdef HAVE_NTGUI + return -1; /* W32_TODO : bitmap support */ +#endif /* HAVE_NTGUI */ + +#ifdef HAVE_X_WINDOWS + Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); + unsigned int width, height; + Pixmap bitmap; + int xhot, yhot, result, id; + Lisp_Object found; + int fd; + char *filename; + + /* Look for an existing bitmap with the same name. */ + for (id = 0; id < dpyinfo->bitmaps_last; ++id) + { + if (dpyinfo->bitmaps[id].refcount + && dpyinfo->bitmaps[id].file + && !strcmp (dpyinfo->bitmaps[id].file, (char *) SDATA (file))) + { + ++dpyinfo->bitmaps[id].refcount; + return id + 1; + } + } + + /* Search bitmap-file-path for the file, if appropriate. */ + fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil); + if (fd < 0) + return -1; + emacs_close (fd); + + filename = (char *) SDATA (found); + + result = XReadBitmapFile (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + filename, &width, &height, &bitmap, &xhot, &yhot); + if (result != BitmapSuccess) + return -1; + + id = x_allocate_bitmap_record (f); + dpyinfo->bitmaps[id - 1].pixmap = bitmap; + dpyinfo->bitmaps[id - 1].have_mask = 0; + dpyinfo->bitmaps[id - 1].refcount = 1; + dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (SBYTES (file) + 1); + dpyinfo->bitmaps[id - 1].depth = 1; + dpyinfo->bitmaps[id - 1].height = height; + dpyinfo->bitmaps[id - 1].width = width; + strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file)); + + return id; +#endif /* HAVE_X_WINDOWS */ +} + +/* Free bitmap B. */ + +static void +Free_Bitmap_Record (dpyinfo, bm) + Display_Info *dpyinfo; + Bitmap_Record *bm; +{ +#ifdef HAVE_X_WINDOWS + XFreePixmap (dpyinfo->display, bm->pixmap); + if (bm->have_mask) + XFreePixmap (dpyinfo->display, bm->mask); +#endif /* HAVE_X_WINDOWS */ + +#ifdef HAVE_NTGUI + DeleteObject (bm->pixmap); +#endif /* HAVE_NTGUI */ + +#ifdef MAC_OS + xfree (bm->bitmap_data); /* Added ++kfs */ + bm->bitmap_data = NULL; +#endif /* MAC_OS */ + + if (bm->file) + { + xfree (bm->file); + bm->file = NULL; + } +} + +/* Remove reference to bitmap with id number ID. */ + +void +x_destroy_bitmap (f, id) + FRAME_PTR f; + int id; +{ + Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); + + if (id > 0) + { + Bitmap_Record *bm = &dpyinfo->bitmaps[id - 1]; + + if (--bm->refcount == 0) + { + BLOCK_INPUT; + Free_Bitmap_Record (dpyinfo, bm); + UNBLOCK_INPUT; + } + } +} + +/* Free all the bitmaps for the display specified by DPYINFO. */ + +void +x_destroy_all_bitmaps (dpyinfo) + Display_Info *dpyinfo; +{ + int i; + Bitmap_Record *bm = dpyinfo->bitmaps; + + for (i = 0; i < dpyinfo->bitmaps_last; i++, bm++) + if (bm->refcount > 0) + Free_Bitmap_Record (dpyinfo, bm); + + dpyinfo->bitmaps_last = 0; +} + + +#ifdef HAVE_X_WINDOWS + +/* Useful functions defined in the section + `Image type independent image structures' below. */ + +static unsigned long four_corners_best P_ ((XImagePtr ximg, unsigned long width, + unsigned long height)); + +static int x_create_x_image_and_pixmap P_ ((struct frame *f, int width, int height, + int depth, XImagePtr *ximg, + Pixmap *pixmap)); + +static void x_destroy_x_image P_ ((XImagePtr ximg)); + + +/* Create a mask of a bitmap. Note is this not a perfect mask. + It's nicer with some borders in this context */ + +int +x_create_bitmap_mask (f, id) + struct frame *f; + int id; +{ + Pixmap pixmap, mask; + XImagePtr ximg, mask_img; + unsigned long width, height; + int result; + unsigned long bg; + unsigned long x, y, xp, xm, yp, ym; + GC gc; + + Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); + + if (!(id > 0)) + return -1; + + pixmap = x_bitmap_pixmap (f, id); + width = x_bitmap_width (f, id); + height = x_bitmap_height (f, id); + + BLOCK_INPUT; + ximg = XGetImage (FRAME_X_DISPLAY (f), pixmap, 0, 0, width, height, + ~0, ZPixmap); + + if (!ximg) + { + UNBLOCK_INPUT; + return -1; + } + + result = x_create_x_image_and_pixmap (f, width, height, 1, &mask_img, &mask); + + UNBLOCK_INPUT; + if (!result) + { + XDestroyImage (ximg); + return -1; + } + + bg = four_corners_best (ximg, width, height); + + for (y = 0; y < ximg->height; ++y) + { + for (x = 0; x < ximg->width; ++x) + { + xp = x != ximg->width - 1 ? x + 1 : 0; + xm = x != 0 ? x - 1 : ximg->width - 1; + yp = y != ximg->height - 1 ? y + 1 : 0; + ym = y != 0 ? y - 1 : ximg->height - 1; + if (XGetPixel (ximg, x, y) == bg + && XGetPixel (ximg, x, yp) == bg + && XGetPixel (ximg, x, ym) == bg + && XGetPixel (ximg, xp, y) == bg + && XGetPixel (ximg, xp, yp) == bg + && XGetPixel (ximg, xp, ym) == bg + && XGetPixel (ximg, xm, y) == bg + && XGetPixel (ximg, xm, yp) == bg + && XGetPixel (ximg, xm, ym) == bg) + XPutPixel (mask_img, x, y, 0); + else + XPutPixel (mask_img, x, y, 1); + } + } + + xassert (interrupt_input_blocked); + gc = XCreateGC (FRAME_X_DISPLAY (f), mask, 0, NULL); + XPutImage (FRAME_X_DISPLAY (f), mask, gc, mask_img, 0, 0, 0, 0, + width, height); + XFreeGC (FRAME_X_DISPLAY (f), gc); + + dpyinfo->bitmaps[id - 1].have_mask = 1; + dpyinfo->bitmaps[id - 1].mask = mask; + + XDestroyImage (ximg); + x_destroy_x_image (mask_img); + + return 0; +} + +#endif /* HAVE_X_WINDOWS */ + + +/*********************************************************************** + Image types + ***********************************************************************/ + +/* Value is the number of elements of vector VECTOR. */ + +#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR)) + +/* List of supported image types. Use define_image_type to add new + types. Use lookup_image_type to find a type for a given symbol. */ + +static struct image_type *image_types; + +/* The symbol `xbm' which is used as the type symbol for XBM images. */ + +Lisp_Object Qxbm; + +/* Keywords. */ + +extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile; +extern Lisp_Object QCdata, QCtype; +extern Lisp_Object Qcenter; +Lisp_Object QCascent, QCmargin, QCrelief; +Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask; +Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask; + +/* Other symbols. */ + +Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic; + +/* Time in seconds after which images should be removed from the cache + if not displayed. */ + +Lisp_Object Vimage_cache_eviction_delay; + +/* Function prototypes. */ + +static void define_image_type P_ ((struct image_type *type)); +static struct image_type *lookup_image_type P_ ((Lisp_Object symbol)); +static void image_error P_ ((char *format, Lisp_Object, Lisp_Object)); +static void x_laplace P_ ((struct frame *, struct image *)); +static void x_emboss P_ ((struct frame *, struct image *)); +static int x_build_heuristic_mask P_ ((struct frame *, struct image *, + Lisp_Object)); + + +/* Define a new image type from TYPE. This adds a copy of TYPE to + image_types and adds the symbol *TYPE->type to Vimage_types. */ + +static void +define_image_type (type) + struct image_type *type; +{ + /* Make a copy of TYPE to avoid a bus error in a dumped Emacs. + The initialized data segment is read-only. */ + struct image_type *p = (struct image_type *) xmalloc (sizeof *p); + bcopy (type, p, sizeof *p); + p->next = image_types; + image_types = p; + Vimage_types = Fcons (*p->type, Vimage_types); +} + + +/* Look up image type SYMBOL, and return a pointer to its image_type + structure. Value is null if SYMBOL is not a known image type. */ + +static INLINE struct image_type * +lookup_image_type (symbol) + Lisp_Object symbol; +{ + struct image_type *type; + + for (type = image_types; type; type = type->next) + if (EQ (symbol, *type->type)) + break; + + return type; +} + + +/* Value is non-zero if OBJECT is a valid Lisp image specification. A + valid image specification is a list whose car is the symbol + `image', and whose rest is a property list. The property list must + contain a value for key `:type'. That value must be the name of a + supported image type. The rest of the property list depends on the + image type. */ + +int +valid_image_p (object) + Lisp_Object object; +{ + int valid_p = 0; + + if (IMAGEP (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; +} + + +/* Log error message with format string FORMAT and argument ARG. + Signaling an error, e.g. when an image cannot be loaded, is not a + good idea because this would interrupt redisplay, and the error + message display would lead to another redisplay. This function + therefore simply displays a message. */ + +static void +image_error (format, arg1, arg2) + char *format; + Lisp_Object arg1, arg2; +{ + add_to_log (format, arg1, arg2); +} + + + +/*********************************************************************** + Image specifications + ***********************************************************************/ + +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, + IMAGE_FUNCTION_VALUE, + IMAGE_NUMBER_VALUE, + IMAGE_BOOL_VALUE +}; + +/* Structure used when parsing image specifications. */ + +struct image_keyword +{ + /* Name of keyword. */ + char *name; + + /* The type of value allowed. */ + enum image_value_type type; + + /* Non-zero means key must be present. */ + int mandatory_p; + + /* Used to recognize duplicate keywords in a property list. */ + int count; + + /* The value that was found. */ + Lisp_Object value; +}; + + +static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *, + int, Lisp_Object)); +static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *)); + + +/* Parse image spec SPEC according to KEYWORDS. A valid image spec + has the format (image KEYWORD VALUE ...). One of the keyword/ + value pairs must be `:type TYPE'. KEYWORDS is a vector of + image_keywords structures of size NKEYWORDS describing other + allowed keyword/value pairs. Value is non-zero if SPEC is valid. */ + +static int +parse_image_spec (spec, keywords, nkeywords, type) + Lisp_Object spec; + struct image_keyword *keywords; + int nkeywords; + Lisp_Object type; +{ + int i; + Lisp_Object plist; + + if (!IMAGEP (spec)) + return 0; + + plist = XCDR (spec); + while (CONSP (plist)) + { + Lisp_Object key, value; + + /* First element of a pair must be a symbol. */ + key = XCAR (plist); + plist = XCDR (plist); + if (!SYMBOLP (key)) + return 0; + + /* There must follow a value. */ + if (!CONSP (plist)) + return 0; + value = XCAR (plist); + plist = XCDR (plist); + + /* Find key in KEYWORDS. Error if not found. */ + for (i = 0; i < nkeywords; ++i) + if (strcmp (keywords[i].name, SDATA (SYMBOL_NAME (key))) == 0) + break; + + if (i == nkeywords) + continue; + + /* Record that we recognized the keyword. If a keywords + was found more than once, it's an error. */ + keywords[i].value = value; + ++keywords[i].count; + + if (keywords[i].count > 1) + return 0; + + /* Check type of value against allowed type. */ + switch (keywords[i].type) + { + case IMAGE_STRING_VALUE: + if (!STRINGP (value)) + 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; + break; + + case IMAGE_POSITIVE_INTEGER_VALUE: + if (!INTEGERP (value) || XINT (value) <= 0) + 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; + else if (INTEGERP (value) + && XINT (value) >= 0 + && XINT (value) <= 100) + break; + return 0; + + case IMAGE_NON_NEGATIVE_INTEGER_VALUE: + if (!INTEGERP (value) || XINT (value) < 0) + return 0; + break; + + case IMAGE_DONT_CHECK_VALUE_TYPE: + break; + + case IMAGE_FUNCTION_VALUE: + value = indirect_function (value); + if (SUBRP (value) + || COMPILEDP (value) + || (CONSP (value) && EQ (XCAR (value), Qlambda))) + break; + return 0; + + case IMAGE_NUMBER_VALUE: + if (!INTEGERP (value) && !FLOATP (value)) + return 0; + break; + + case IMAGE_INTEGER_VALUE: + if (!INTEGERP (value)) + return 0; + break; + + case IMAGE_BOOL_VALUE: + if (!NILP (value) && !EQ (value, Qt)) + return 0; + break; + + default: + abort (); + break; + } + + if (EQ (key, QCtype) && !EQ (type, value)) + return 0; + } + + /* Check that all mandatory fields are present. */ + for (i = 0; i < nkeywords; ++i) + if (keywords[i].mandatory_p && keywords[i].count == 0) + return 0; + + return NILP (plist); +} + + +/* Return the value of KEY in image specification SPEC. Value is nil + if KEY is not present in SPEC. if FOUND is not null, set *FOUND + to 1 if KEY was found in SPEC, set it to 0 otherwise. */ + +static Lisp_Object +image_spec_value (spec, key, found) + Lisp_Object spec, key; + int *found; +{ + Lisp_Object tail; + + xassert (valid_image_p (spec)); + + for (tail = XCDR (spec); + CONSP (tail) && CONSP (XCDR (tail)); + tail = XCDR (XCDR (tail))) + { + if (EQ (XCAR (tail), key)) + { + if (found) + *found = 1; + return XCAR (XCDR (tail)); + } + } + + if (found) + *found = 0; + return Qnil; +} + + +DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0, + doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT). +PIXELS non-nil means return the size in pixels, otherwise return the +size in canonical character units. +FRAME is the frame on which the image will be displayed. FRAME nil +or omitted means use the selected frame. */) + (spec, pixels, frame) + Lisp_Object spec, pixels, frame; +{ + Lisp_Object size; + + size = Qnil; + if (valid_image_p (spec)) + { + 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->hmargin; + int height = img->height + 2 * img->vmargin; + + if (NILP (pixels)) + size = Fcons (make_float ((double) width / FRAME_COLUMN_WIDTH (f)), + make_float ((double) height / FRAME_LINE_HEIGHT (f))); + else + size = Fcons (make_number (width), make_number (height)); + } + else + error ("Invalid image specification"); + + return size; +} + + +DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0, + doc: /* Return t if image SPEC has a mask bitmap. +FRAME is the frame on which the image will be displayed. FRAME nil +or omitted means use the selected frame. */) + (spec, frame) + Lisp_Object spec, frame; +{ + Lisp_Object mask; + + mask = Qnil; + if (valid_image_p (spec)) + { + struct frame *f = check_x_frame (frame); + int id = lookup_image (f, spec); + struct image *img = IMAGE_FROM_ID (f, id); + if (img->mask) + mask = Qt; + } + else + error ("Invalid image specification"); + + return mask; +} + + +/*********************************************************************** + Image type independent image structures + ***********************************************************************/ + +static struct image *make_image P_ ((Lisp_Object spec, unsigned hash)); +static void free_image P_ ((struct frame *f, struct image *img)); + + +/* Allocate and return a new image structure for image specification + SPEC. SPEC has a hash value of HASH. */ + +static struct image * +make_image (spec, hash) + Lisp_Object spec; + unsigned hash; +{ + struct image *img = (struct image *) xmalloc (sizeof *img); + + xassert (valid_image_p (spec)); + bzero (img, sizeof *img); + img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL)); + xassert (img->type != NULL); + img->spec = spec; + img->data.lisp_val = Qnil; + img->ascent = DEFAULT_IMAGE_ASCENT; + img->hash = hash; + return img; +} + + +/* Free image IMG which was used on frame F, including its resources. */ + +static void +free_image (f, img) + struct frame *f; + struct image *img; +{ + if (img) + { + struct image_cache *c = FRAME_X_IMAGE_CACHE (f); + + /* Remove IMG from the hash table of its cache. */ + if (img->prev) + img->prev->next = img->next; + else + c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next; + + if (img->next) + img->next->prev = img->prev; + + c->images[img->id] = NULL; + + /* Free resources, then free IMG. */ + img->type->free (f, img); + xfree (img); + } +} + + +/* Prepare image IMG for display on frame F. Must be called before + drawing an image. */ + +void +prepare_image_for_display (f, img) + struct frame *f; + struct image *img; +{ + EMACS_TIME t; + + /* We're about to display IMG, so set its timestamp to `now'. */ + EMACS_GET_TIME (t); + img->timestamp = EMACS_SECS (t); + + /* If IMG doesn't have a pixmap yet, load it now, using the image + type dependent loader function. */ + if (img->pixmap == NO_PIXMAP && !img->load_failed_p) + img->load_failed_p = img->type->load (f, img) == 0; +} + + +/* Value is the number of pixels for the ascent of image IMG when + drawn in face FACE. */ + +int +image_ascent (img, face) + struct image *img; + struct face *face; +{ + int height = img->height + img->vmargin; + int ascent; + + if (img->ascent == CENTERED_IMAGE_ASCENT) + { + if (face->font) + { +#ifdef HAVE_NTGUI + /* W32 specific version. Why?. ++kfs */ + ascent = height / 2 - (FONT_DESCENT(face->font) + - FONT_BASE(face->font)) / 2; +#else + /* This expression is arranged so that if the image can't be + exactly centered, it will be moved slightly up. This is + because a typical font is `top-heavy' (due to the presence + uppercase letters), so the image placement should err towards + being top-heavy too. It also just generally looks better. */ + ascent = (height + face->font->ascent - face->font->descent + 1) / 2; +#endif /* HAVE_NTGUI */ + } + else + ascent = height / 2; + } + else + ascent = (int) (height * img->ascent / 100.0); + + return ascent; +} + + +/* Image background colors. */ + +/* Find the "best" corner color of a bitmap. + On W32, XIMG is assumed to a device context with the bitmap selected. */ + +static RGB_PIXEL_COLOR +four_corners_best (ximg, width, height) + XImagePtr_or_DC ximg; + unsigned long width, height; +{ + RGB_PIXEL_COLOR corners[4], best; + int i, best_count; + + /* Get the colors at the corners of ximg. */ + corners[0] = GET_PIXEL (ximg, 0, 0); + corners[1] = GET_PIXEL (ximg, width - 1, 0); + corners[2] = GET_PIXEL (ximg, width - 1, height - 1); + corners[3] = GET_PIXEL (ximg, 0, height - 1); + + /* Choose the most frequently found color as background. */ + for (i = best_count = 0; i < 4; ++i) + { + int j, n; + + for (j = n = 0; j < 4; ++j) + if (corners[i] == corners[j]) + ++n; + + if (n > best_count) + best = corners[i], best_count = n; + } + + return best; +} + +/* Portability macros */ + +#ifdef HAVE_NTGUI + +#define Destroy_Image(img_dc, prev) \ + do { SelectObject (img_dc, prev); DeleteDC (img_dc); } while (0) + +#define Free_Pixmap(display, pixmap) \ + DeleteObject (pixmap) + +#else + +#define Destroy_Image(ximg, dummy) \ + XDestroyImage (ximg) + +#define Free_Pixmap(display, pixmap) \ + XFreePixmap (display, pixmap) + +#endif /* HAVE_NTGUI */ + + +/* Return the `background' field of IMG. If IMG doesn't have one yet, + it is guessed heuristically. If non-zero, XIMG is an existing + XImage object (or device context with the image selected on W32) to + use for the heuristic. */ + +RGB_PIXEL_COLOR +image_background (img, f, ximg) + struct image *img; + struct frame *f; + XImagePtr_or_DC ximg; +{ + if (! img->background_valid) + /* IMG doesn't have a background yet, try to guess a reasonable value. */ + { + int free_ximg = !ximg; +#ifdef HAVE_NTGUI + HGDIOBJ prev; +#endif /* HAVE_NTGUI */ + + if (free_ximg) + { +#ifndef HAVE_NTGUI + ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap, + 0, 0, img->width, img->height, ~0, ZPixmap); +#else + HDC frame_dc = get_frame_dc (f); + ximg = CreateCompatibleDC (frame_dc); + release_frame_dc (f, frame_dc); + prev = SelectObject (ximg, img->pixmap); +#endif /* !HAVE_NTGUI */ + } + + img->background = four_corners_best (ximg, img->width, img->height); + + if (free_ximg) + Destroy_Image (ximg, prev); + + img->background_valid = 1; + } + + return img->background; +} + +/* Return the `background_transparent' field of IMG. If IMG doesn't + have one yet, it is guessed heuristically. If non-zero, MASK is an + existing XImage object to use for the heuristic. */ + +int +image_background_transparent (img, f, mask) + struct image *img; + struct frame *f; + XImagePtr_or_DC mask; +{ + if (! img->background_transparent_valid) + /* IMG doesn't have a background yet, try to guess a reasonable value. */ + { + if (img->mask) + { + int free_mask = !mask; +#ifdef HAVE_NTGUI + HGDIOBJ prev; +#endif /* HAVE_NTGUI */ + + if (free_mask) + { +#ifndef HAVE_NTGUI + mask = XGetImage (FRAME_X_DISPLAY (f), img->mask, + 0, 0, img->width, img->height, ~0, ZPixmap); +#else + HDC frame_dc = get_frame_dc (f); + mask = CreateCompatibleDC (frame_dc); + release_frame_dc (f, frame_dc); + prev = SelectObject (mask, img->mask); +#endif /* HAVE_NTGUI */ + } + + img->background_transparent + = (four_corners_best (mask, img->width, img->height) == PIX_MASK_RETAIN (f)); + + if (free_mask) + Destroy_Image (mask, prev); + } + else + img->background_transparent = 0; + + img->background_transparent_valid = 1; + } + + return img->background_transparent; +} + + +/*********************************************************************** + Helper functions for X image types + ***********************************************************************/ + +static void x_clear_image_1 P_ ((struct frame *, struct image *, int, + int, int)); +static void x_clear_image P_ ((struct frame *f, struct image *img)); +static unsigned long x_alloc_image_color P_ ((struct frame *f, + struct image *img, + Lisp_Object color_name, + unsigned long dflt)); + + +/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means + free the pixmap if any. MASK_P non-zero means clear the mask + pixmap if any. COLORS_P non-zero means free colors allocated for + the image, if any. */ + +static void +x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p) + struct frame *f; + struct image *img; + int pixmap_p, mask_p, colors_p; +{ + if (pixmap_p && img->pixmap) + { + Free_Pixmap (FRAME_X_DISPLAY (f), img->pixmap); + img->pixmap = NO_PIXMAP; + img->background_valid = 0; + } + + if (mask_p && img->mask) + { + Free_Pixmap (FRAME_X_DISPLAY (f), img->mask); + img->mask = NO_PIXMAP; + img->background_transparent_valid = 0; + } + + if (colors_p && img->ncolors) + { + /* MAC_TODO: color table support. */ + /* W32_TODO: color table support. */ +#ifdef HAVE_X_WINDOWS + x_free_colors (f, img->colors, img->ncolors); +#endif /* HAVE_X_WINDOWS */ + xfree (img->colors); + img->colors = NULL; + img->ncolors = 0; + } +} + +/* Free X resources of image IMG which is used on frame F. */ + +static void +x_clear_image (f, img) + struct frame *f; + struct image *img; +{ + BLOCK_INPUT; + x_clear_image_1 (f, img, 1, 1, 1); + UNBLOCK_INPUT; +} + + +/* Allocate color COLOR_NAME for image IMG on frame F. If color + cannot be allocated, use DFLT. Add a newly allocated color to + IMG->colors, so that it can be freed again. Value is the pixel + color. */ + +static unsigned long +x_alloc_image_color (f, img, color_name, dflt) + struct frame *f; + struct image *img; + Lisp_Object color_name; + unsigned long dflt; +{ + XColor color; + unsigned long result; + + xassert (STRINGP (color_name)); + + if (x_defined_color (f, SDATA (color_name), &color, 1)) + { + /* This isn't called frequently so we get away with simply + reallocating the color vector to the needed size, here. */ + ++img->ncolors; + img->colors = + (unsigned long *) xrealloc (img->colors, + img->ncolors * sizeof *img->colors); + img->colors[img->ncolors - 1] = color.pixel; + result = color.pixel; + } + else + result = dflt; + + return result; +} + + + +/*********************************************************************** + Image Cache + ***********************************************************************/ + +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 + heap. Call free_image_cache to free an image cache. */ + +struct image_cache * +make_image_cache () +{ + struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c); + int size; + + bzero (c, sizeof *c); + c->size = 50; + c->images = (struct image **) xmalloc (c->size * sizeof *c->images); + size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets; + c->buckets = (struct image **) xmalloc (size); + bzero (c->buckets, size); + return c; +} + + +/* Free image cache of frame F. Be aware that X frames share images + caches. */ + +void +free_image_cache (f) + struct frame *f; +{ + struct image_cache *c = FRAME_X_IMAGE_CACHE (f); + if (c) + { + int i; + + /* Cache should not be referenced by any frame when freed. */ + xassert (c->refcount == 0); + + for (i = 0; i < c->used; ++i) + free_image (f, c->images[i]); + xfree (c->images); + xfree (c->buckets); + xfree (c); + FRAME_X_IMAGE_CACHE (f) = NULL; + } +} + + +/* Clear image cache of frame F. FORCE_P non-zero means free all + images. FORCE_P zero means clear only images that haven't been + displayed for some time. Should be called from time to time to + reduce the number of loaded images. If image-eviction-seconds is + non-nil, this frees images in the cache which weren't displayed for + at least that many seconds. */ + +void +clear_image_cache (f, force_p) + struct frame *f; + int force_p; +{ + struct image_cache *c = FRAME_X_IMAGE_CACHE (f); + + if (c && INTEGERP (Vimage_cache_eviction_delay)) + { + EMACS_TIME t; + unsigned long old; + int i, nfreed; + + EMACS_GET_TIME (t); + old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay); + + /* Block input so that we won't be interrupted by a SIGIO + while being in an inconsistent state. */ + BLOCK_INPUT; + + for (i = nfreed = 0; i < c->used; ++i) + { + struct image *img = c->images[i]; + if (img != NULL + && (force_p || img->timestamp < old)) + { + free_image (f, img); + ++nfreed; + } + } + + /* We may be clearing the image cache because, for example, + Emacs was iconified for a longer period of time. In that + case, current matrices may still contain references to + images freed above. So, clear these matrices. */ + if (nfreed) + { + Lisp_Object tail, frame; + + FOR_EACH_FRAME (tail, frame) + { + struct frame *f = XFRAME (frame); + if (FRAME_WINDOW_P (f) + && FRAME_X_IMAGE_CACHE (f) == c) + clear_current_matrices (f); + } + + ++windows_or_buffers_changed; + } + + UNBLOCK_INPUT; + } +} + + +DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache, + 0, 1, 0, + doc: /* Clear the image cache of FRAME. +FRAME nil or omitted means use the selected frame. +FRAME t means clear the image caches of all frames. */) + (frame) + Lisp_Object frame; +{ + if (EQ (frame, Qt)) + { + Lisp_Object tail; + + FOR_EACH_FRAME (tail, frame) + if (FRAME_WINDOW_P (XFRAME (frame))) + clear_image_cache (XFRAME (frame), 1); + } + else + clear_image_cache (check_x_frame (frame), 1); + + return Qnil; +} + + +/* 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) + { + Free_Pixmap (FRAME_X_DISPLAY (f), img->mask); + img->mask = NO_PIXMAP; + } + } + + + /* 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). */ + +int +lookup_image (f, spec) + struct frame *f; + Lisp_Object spec; +{ + struct image_cache *c = FRAME_X_IMAGE_CACHE (f); + struct image *img; + int i; + unsigned hash; + struct gcpro gcpro1; + EMACS_TIME now; + + /* F must be a window-system frame, and SPEC must be a valid image + specification. */ + xassert (FRAME_WINDOW_P (f)); + xassert (valid_image_p (spec)); + + GCPRO1 (spec); + + /* Look up SPEC in the hash table of the image cache. */ + hash = sxhash (spec, 0); + i = hash % IMAGE_CACHE_BUCKETS_SIZE; + + for (img = c->buckets[i]; img; img = img->next) + if (img->hash == hash && !NILP (Fequal (img->spec, spec))) + break; + + /* 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); + 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->load_failed_p) + { + Lisp_Object value; + + value = image_spec_value (spec, QCwidth, NULL); + img->width = (INTEGERP (value) + ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH); + value = image_spec_value (spec, QCheight, NULL); + img->height = (INTEGERP (value) + ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT); + } + else + { + /* Handle image type independent image attributes + `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF', + `:background COLOR'. */ + Lisp_Object ascent, margin, relief, bg; + + ascent = image_spec_value (spec, QCascent, NULL); + if (INTEGERP (ascent)) + img->ascent = XFASTINT (ascent); + else if (EQ (ascent, Qcenter)) + img->ascent = CENTERED_IMAGE_ASCENT; + + margin = image_spec_value (spec, QCmargin, NULL); + if (INTEGERP (margin) && XINT (margin) >= 0) + 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->hmargin += abs (img->relief); + img->vmargin += abs (img->relief); + } + + if (! img->background_valid) + { + bg = image_spec_value (img->spec, QCbackground, NULL); + if (!NILP (bg)) + { + img->background + = x_alloc_image_color (f, img, bg, + FRAME_BACKGROUND_PIXEL (f)); + img->background_valid = 1; + } + } + + /* Do image transformations and compute masks, unless we + don't have the image yet. */ + if (!EQ (*img->type->type, Qpostscript)) + postprocess_image (f, img); + } + + UNBLOCK_INPUT; + } + + /* We're using IMG, so set its timestamp to `now'. */ + EMACS_GET_TIME (now); + img->timestamp = EMACS_SECS (now); + + UNGCPRO; + + /* Value is the image id. */ + return img->id; +} + + +/* Cache image IMG in the image cache of frame F. */ + +static void +cache_image (f, img) + struct frame *f; + struct image *img; +{ + struct image_cache *c = FRAME_X_IMAGE_CACHE (f); + int i; + + /* Find a free slot in c->images. */ + for (i = 0; i < c->used; ++i) + if (c->images[i] == NULL) + break; + + /* If no free slot found, maybe enlarge c->images. */ + if (i == c->used && c->used == c->size) + { + c->size *= 2; + c->images = (struct image **) xrealloc (c->images, + c->size * sizeof *c->images); + } + + /* Add IMG to c->images, and assign IMG an id. */ + c->images[i] = img; + img->id = i; + if (i == c->used) + ++c->used; + + /* Add IMG to the cache's hash table. */ + i = img->hash % IMAGE_CACHE_BUCKETS_SIZE; + img->next = c->buckets[i]; + if (img->next) + img->next->prev = img; + img->prev = NULL; + c->buckets[i] = img; +} + + +/* Call FN on every image in the image cache of frame F. Used to mark + Lisp Objects in the image cache. */ + +void +forall_images_in_image_cache (f, fn) + struct frame *f; + void (*fn) P_ ((struct image *img)); +{ + if (FRAME_LIVE_P (f) && FRAME_WINDOW_P (f)) + { + struct image_cache *c = FRAME_X_IMAGE_CACHE (f); + if (c) + { + int i; + for (i = 0; i < c->used; ++i) + if (c->images[i]) + fn (c->images[i]); + } + } +} + + + +/*********************************************************************** + X / MAC / W32 support code + ***********************************************************************/ + +#ifdef HAVE_NTGUI + +/* Macro for defining functions that will be loaded from image DLLs. */ +#define DEF_IMGLIB_FN(func) FARPROC fn_##func + +/* Macro for loading those image functions from the library. */ +#define LOAD_IMGLIB_FN(lib,func) { \ + fn_##func = (void *) GetProcAddress (lib, #func); \ + if (!fn_##func) return 0; \ + } + +#endif /* HAVE_NTGUI */ + +static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int, + XImagePtr *, Pixmap *)); +static void x_destroy_x_image P_ ((XImagePtr)); +static void x_put_x_image P_ ((struct frame *, XImagePtr, Pixmap, int, int)); + + +/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on + frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created. + Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated + via xmalloc. Print error messages via image_error if an error + occurs. Value is non-zero if successful. + + On W32, a DEPTH of zero signifies a 24 bit image, otherwise DEPTH + should indicate the bit depth of the image. */ + +static int +x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap) + struct frame *f; + int width, height, depth; + XImagePtr *ximg; + Pixmap *pixmap; +{ +#ifdef HAVE_X_WINDOWS + Display *display = FRAME_X_DISPLAY (f); + Window window = FRAME_X_WINDOW (f); + Screen *screen = FRAME_X_SCREEN (f); + + xassert (interrupt_input_blocked); + + if (depth <= 0) + depth = DefaultDepthOfScreen (screen); + *ximg = XCreateImage (display, DefaultVisualOfScreen (screen), + depth, ZPixmap, 0, NULL, width, height, + depth > 16 ? 32 : depth > 8 ? 16 : 8, 0); + if (*ximg == NULL) + { + image_error ("Unable to allocate X image", Qnil, Qnil); + return 0; + } + + /* Allocate image raster. */ + (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height); + + /* Allocate a pixmap of the same size. */ + *pixmap = XCreatePixmap (display, window, width, height, depth); + if (*pixmap == NO_PIXMAP) + { + x_destroy_x_image (*ximg); + *ximg = NULL; + image_error ("Unable to create X pixmap", Qnil, Qnil); + return 0; + } + + return 1; +#endif /* HAVE_X_WINDOWS */ + +#ifdef HAVE_NTGUI + + BITMAPINFOHEADER *header; + HDC hdc; + int scanline_width_bits; + int remainder; + int palette_colors = 0; + + if (depth == 0) + depth = 24; + + if (depth != 1 && depth != 4 && depth != 8 + && depth != 16 && depth != 24 && depth != 32) + { + image_error ("Invalid image bit depth specified", Qnil, Qnil); + return 0; + } + + scanline_width_bits = width * depth; + remainder = scanline_width_bits % 32; + + if (remainder) + scanline_width_bits += 32 - remainder; + + /* Bitmaps with a depth less than 16 need a palette. */ + /* BITMAPINFO structure already contains the first RGBQUAD. */ + if (depth < 16) + palette_colors = 1 << depth - 1; + + *ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD)); + if (*ximg == NULL) + { + image_error ("Unable to allocate memory for XImage", Qnil, Qnil); + return 0; + } + + header = &((*ximg)->info.bmiHeader); + bzero (&((*ximg)->info), sizeof (BITMAPINFO)); + header->biSize = sizeof (*header); + header->biWidth = width; + header->biHeight = -height; /* negative indicates a top-down bitmap. */ + header->biPlanes = 1; + header->biBitCount = depth; + header->biCompression = BI_RGB; + header->biClrUsed = palette_colors; + + /* TODO: fill in palette. */ + if (depth == 1) + { + (*ximg)->info.bmiColors[0].rgbBlue = 0; + (*ximg)->info.bmiColors[0].rgbGreen = 0; + (*ximg)->info.bmiColors[0].rgbRed = 0; + (*ximg)->info.bmiColors[0].rgbReserved = 0; + (*ximg)->info.bmiColors[1].rgbBlue = 255; + (*ximg)->info.bmiColors[1].rgbGreen = 255; + (*ximg)->info.bmiColors[1].rgbRed = 255; + (*ximg)->info.bmiColors[1].rgbReserved = 0; + } + + hdc = get_frame_dc (f); + + /* Create a DIBSection and raster array for the bitmap, + and store its handle in *pixmap. */ + *pixmap = CreateDIBSection (hdc, &((*ximg)->info), + (depth < 16) ? DIB_PAL_COLORS : DIB_RGB_COLORS, + &((*ximg)->data), NULL, 0); + + /* Realize display palette and garbage all frames. */ + release_frame_dc (f, hdc); + + if (*pixmap == NULL) + { + DWORD err = GetLastError(); + Lisp_Object errcode; + /* All system errors are < 10000, so the following is safe. */ + XSETINT (errcode, (int) err); + image_error ("Unable to create bitmap, error code %d", errcode, Qnil); + x_destroy_x_image (*ximg); + return 0; + } + + return 1; + +#endif /* HAVE_NTGUI */ + +#ifdef MAC_OS + Display *display = FRAME_X_DISPLAY (f); + Window window = FRAME_X_WINDOW (f); + + xassert (interrupt_input_blocked); + + /* Allocate a pixmap of the same size. */ + *pixmap = XCreatePixmap (display, window, width, height, depth); + if (*pixmap == NO_PIXMAP) + { + x_destroy_x_image (*ximg); + *ximg = NULL; + image_error ("Unable to create X pixmap", Qnil, Qnil); + return 0; + } + + LockPixels (GetGWorldPixMap (*pixmap)); + *ximg = *pixmap; + return 1; + +#endif /* MAC_OS */ +} + + +/* Destroy XImage XIMG. Free XIMG->data. */ + +static void +x_destroy_x_image (ximg) + XImagePtr ximg; +{ + xassert (interrupt_input_blocked); + if (ximg) + { +#ifdef HAVE_X_WINDOWS + xfree (ximg->data); + ximg->data = NULL; + XDestroyImage (ximg); +#endif /* HAVE_X_WINDOWS */ +#ifdef HAVE_NTGUI + /* Data will be freed by DestroyObject. */ + ximg->data = NULL; + xfree (ximg); +#endif /* HAVE_NTGUI */ +#ifdef MAC_OS + XDestroyImage (ximg); +#endif /* MAC_OS */ + } +} + + +/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT + are width and height of both the image and pixmap. */ + +static void +x_put_x_image (f, ximg, pixmap, width, height) + struct frame *f; + XImagePtr ximg; + Pixmap pixmap; + int width, height; +{ +#ifdef HAVE_X_WINDOWS + GC gc; + + xassert (interrupt_input_blocked); + gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL); + XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height); + XFreeGC (FRAME_X_DISPLAY (f), gc); +#endif /* HAVE_X_WINDOWS */ + +#ifdef HAVE_NTGUI +#if 0 /* I don't think this is necessary looking at where it is used. */ + HDC hdc = get_frame_dc (f); + SetDIBits (hdc, pixmap, 0, height, ximg->data, &(ximg->info), DIB_RGB_COLORS); + release_frame_dc (f, hdc); +#endif +#endif /* HAVE_NTGUI */ + +#ifdef MAC_OS + xassert (ximg == pixmap); +#endif /* MAC_OS */ +} + + +/*********************************************************************** + File Handling + ***********************************************************************/ + +static unsigned char *slurp_file P_ ((char *, int *)); + + +/* Find image file FILE. Look in data-directory, then + x-bitmap-file-path. Value is the full name of the file found, or + nil if not found. */ + +Lisp_Object +x_find_image_file (file) + Lisp_Object file; +{ + Lisp_Object file_found, search_path; + struct gcpro gcpro1, gcpro2; + int fd; + + file_found = Qnil; + search_path = Fcons (Vdata_directory, Vx_bitmap_file_path); + GCPRO2 (file_found, search_path); + + /* Try to find FILE in data-directory, then x-bitmap-file-path. */ + fd = openp (search_path, file, Qnil, &file_found, Qnil); + + if (fd == -1) + file_found = Qnil; + else + close (fd); + + UNGCPRO; + return file_found; +} + + +/* Read FILE into memory. Value is a pointer to a buffer allocated + with xmalloc holding FILE's contents. Value is null if an error + occurred. *SIZE is set to the size of the file. */ + +static unsigned char * +slurp_file (file, size) + char *file; + int *size; +{ + FILE *fp = NULL; + unsigned char *buf = NULL; + struct stat st; + + if (stat (file, &st) == 0 + && (fp = fopen (file, "rb")) != NULL + && (buf = (char *) xmalloc (st.st_size), + fread (buf, 1, st.st_size, fp) == st.st_size)) + { + *size = st.st_size; + fclose (fp); + } + else + { + if (fp) + fclose (fp); + if (buf) + { + xfree (buf); + buf = NULL; + } + } + + return buf; +} + + + +#ifdef MAC_OS + +/*********************************************************************** + MAC Image Load Functions + ***********************************************************************/ + +static int image_load_quicktime P_ ((struct frame *, struct image *img, + OSType)); +#ifdef MAC_OSX +static int image_load_quartz2d P_ ((struct frame *, struct image *img, int)); +#endif + +static OSErr +find_image_fsspec (specified_file, file, fss) + Lisp_Object specified_file, *file; + FSSpec *fss; +{ +#if TARGET_API_MAC_CARBON + FSRef fsr; +#else + Str255 mac_pathname; +#endif + OSErr err; + + *file = x_find_image_file (specified_file); + if (!STRINGP (*file)) + return fnfErr; /* file or directory not found; + incomplete pathname */ + /* Try to open the image file. */ +#if TARGET_API_MAC_CARBON + err = FSPathMakeRef (SDATA (*file), &fsr, NULL); + if (err == noErr) + err = FSGetCatalogInfo (&fsr, kFSCatInfoNone, NULL, NULL, fss, NULL); +#else + if (posix_to_mac_pathname (SDATA (*file), mac_pathname, MAXPATHLEN+1) == 0) + return fnfErr; + c2pstr (mac_pathname); + err = FSMakeFSSpec (0, 0, mac_pathname, fss); +#endif + return err; +} + +static int +image_load_qt_1 (f, img, type, fss, dh) + struct frame *f; + struct image *img; + OSType type; + FSSpec *fss; + Handle dh; +{ + OSErr err; + GraphicsImportComponent gi; + Rect rect; + int width, height; + short draw_all_pixels; + Lisp_Object specified_bg; + XColor color; + XImagePtr ximg; + RGBColor bg_color; + + err = OpenADefaultComponent (GraphicsImporterComponentType, + type, &gi); + if (err != noErr) + { + image_error ("Cannot get importer component for `%s'", img->spec, Qnil); + return 0; + } + if (dh == NULL) + { + /* read from file system spec */ + err = GraphicsImportSetDataFile (gi, fss); + if (err != noErr) + { + image_error ("Cannot set fsspec to graphics importer for '%s'", + img->spec, Qnil); + goto error; + } + } + else + { + /* read from data handle */ + err = GraphicsImportSetDataHandle (gi, dh); + if (err != noErr) + { + image_error ("Cannot set data handle to graphics importer for `%s'", + img->spec, Qnil); + goto error; + } + } + err = GraphicsImportGetNaturalBounds (gi, &rect); + if (err != noErr) + { + image_error ("Error reading `%s'", img->spec, Qnil); + goto error; + } + width = img->width = rect.right - rect.left; + height = img->height = rect.bottom - rect.top; + err = GraphicsImportDoesDrawAllPixels (gi, &draw_all_pixels); +#if 0 + /* Don't check the error code here. It may have an undocumented + value -32766. */ + if (err != noErr) + { + image_error ("Error reading `%s'", img->spec, Qnil); + goto error; + } +#endif + if (draw_all_pixels != graphicsImporterDrawsAllPixels) + { + specified_bg = image_spec_value (img->spec, QCbackground, NULL); + if (!STRINGP (specified_bg) || + !mac_defined_color (f, SDATA (specified_bg), &color, 0)) + { + color.pixel = FRAME_BACKGROUND_PIXEL (f); + color.red = RED16_FROM_ULONG (color.pixel); + color.green = GREEN16_FROM_ULONG (color.pixel); + color.blue = BLUE16_FROM_ULONG (color.pixel); + } + } + + if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) + goto error; + if (draw_all_pixels != graphicsImporterDrawsAllPixels) + { + SetGWorld (ximg, NULL); + bg_color.red = color.red; + bg_color.green = color.green; + bg_color.blue = color.blue; + RGBBackColor (&bg_color); +#if TARGET_API_MAC_CARBON + GetPortBounds (ximg, &rect); + EraseRect (&rect); +#else + EraseRect (&(ximg->portRect)); +#endif + } + GraphicsImportSetGWorld (gi, ximg, NULL); + GraphicsImportDraw (gi); + CloseComponent (gi); + + /* Maybe fill in the background field while we have ximg handy. */ + if (NILP (image_spec_value (img->spec, QCbackground, NULL))) + IMAGE_BACKGROUND (img, f, ximg); + + /* Put the image into the pixmap. */ + x_put_x_image (f, ximg, img->pixmap, width, height); + x_destroy_x_image (ximg); + return 1; + + error: + CloseComponent (gi); + return 0; +} + + +/* Load an image using the QuickTime Graphics Importer. + Note: The alpha channel does not work for PNG images. */ +static int +image_load_quicktime (f, img, type) + struct frame *f; + struct image *img; + OSType type; +{ + Lisp_Object specified_file; + Lisp_Object specified_data; + OSErr err; + + specified_file = image_spec_value (img->spec, QCfile, NULL); + specified_data = image_spec_value (img->spec, QCdata, NULL); + + if (NILP (specified_data)) + { + /* Read from a file */ + Lisp_Object file; + FSSpec fss; + + err = find_image_fsspec (specified_file, &file, &fss); + if (err != noErr) + { + if (err == fnfErr) + image_error ("Cannot find image file `%s'", specified_file, Qnil); + else + image_error ("Cannot open `%s'", file, Qnil); + return 0; + } + return image_load_qt_1 (f, img, type, &fss, NULL); + } + else + { + /* Memory source! */ + int success_p; + Handle dh; + + err = PtrToHand (SDATA (specified_data), &dh, SBYTES (specified_data)); + if (err != noErr) + { + image_error ("Cannot allocate data handle for `%s'", + img->spec, Qnil); + return 0; + } + success_p = image_load_qt_1 (f, img, type, NULL, dh); + DisposeHandle (dh); + return success_p; + } +} + + +#ifdef MAC_OSX +/* Load a PNG/JPEG image using Quartz 2D decoding routines. + CGImageCreateWithPNGDataProvider is provided after Mac OS X 10.2. + So don't use this function directly but determine at runtime + whether it exists. */ +typedef CGImageRef (*CGImageCreateWithPNGDataProviderProcType) + (CGDataProviderRef, const float [], bool, CGColorRenderingIntent); +static CGImageCreateWithPNGDataProviderProcType MyCGImageCreateWithPNGDataProvider; + + +static void +init_image_func_pointer () +{ + if (NSIsSymbolNameDefined ("_CGImageCreateWithPNGDataProvider")) + { + MyCGImageCreateWithPNGDataProvider + = (CGImageCreateWithPNGDataProviderProcType) + NSAddressOfSymbol (NSLookupAndBindSymbol + ("_CGImageCreateWithPNGDataProvider")); + } + else + MyCGImageCreateWithPNGDataProvider = NULL; +} + + +static int +image_load_quartz2d (f, img, png_p) + struct frame *f; + struct image *img; + int png_p; +{ + Lisp_Object file, specified_file; + Lisp_Object specified_data, specified_bg; + struct gcpro gcpro1; + CGDataProviderRef source; + CGImageRef image; + int width, height; + XColor color; + XImagePtr ximg = NULL; + CGContextRef context; + CGRect rectangle; + + /* Open the file. */ + specified_file = image_spec_value (img->spec, QCfile, NULL); + specified_data = image_spec_value (img->spec, QCdata, NULL); + + file = Qnil; + GCPRO1 (file); + + if (NILP (specified_data)) + { + CFStringRef path; + CFURLRef url; + + file = x_find_image_file (specified_file); + if (!STRINGP (file)) + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + UNGCPRO; + return 0; + } + path = CFStringCreateWithCString (NULL, SDATA (file), + kCFStringEncodingUTF8); + url = CFURLCreateWithFileSystemPath (NULL, path, + kCFURLPOSIXPathStyle, 0); + CFRelease (path); + source = CGDataProviderCreateWithURL (url); + CFRelease (url); + } + else + source = CGDataProviderCreateWithData (NULL, SDATA (specified_data), + SBYTES (specified_data), NULL); + + if (png_p) + image = (*MyCGImageCreateWithPNGDataProvider) (source, NULL, FALSE, + kCGRenderingIntentDefault); + else + image = CGImageCreateWithJPEGDataProvider (source, NULL, FALSE, + kCGRenderingIntentDefault); + + CGDataProviderRelease (source); + if (image == NULL) + { + UNGCPRO; + image_error ("Error reading image `%s'", img->spec, Qnil); + return 0; + } + + if (png_p) + { + specified_bg = image_spec_value (img->spec, QCbackground, NULL); + if (!STRINGP (specified_bg) || + !mac_defined_color (f, SDATA (specified_bg), &color, 0)) + { + color.pixel = FRAME_BACKGROUND_PIXEL (f); + color.red = RED16_FROM_ULONG (color.pixel); + color.green = GREEN16_FROM_ULONG (color.pixel); + color.blue = BLUE16_FROM_ULONG (color.pixel); + } + } + width = img->width = CGImageGetWidth (image); + height = img->height = CGImageGetHeight (image); + if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) + { + CGImageRelease (image); + UNGCPRO; + return 0; + } + rectangle = CGRectMake (0, 0, width, height); + QDBeginCGContext (ximg, &context); + if (png_p) + { + CGContextSetRGBFillColor (context, color.red / 65535.0, + color.green / 65535.0, + color.blue / 65535.0, 1.0); + CGContextFillRect (context, rectangle); + } + CGContextDrawImage (context, rectangle, image); + QDEndCGContext (ximg, &context); + CGImageRelease (image); + + /* Maybe fill in the background field while we have ximg handy. */ + if (NILP (image_spec_value (img->spec, QCbackground, NULL))) + IMAGE_BACKGROUND (img, f, ximg); + + /* Put the image into the pixmap. */ + x_put_x_image (f, ximg, img->pixmap, width, height); + x_destroy_x_image (ximg); + UNGCPRO; + return 1; +} +#endif + +#endif /* MAC_OS */ + + +/*********************************************************************** + XBM images + ***********************************************************************/ + +static int xbm_scan P_ ((unsigned char **, unsigned char *, char *, int *)); +static int xbm_load P_ ((struct frame *f, struct image *img)); +static int xbm_load_image P_ ((struct frame *f, struct image *img, + unsigned char *, unsigned char *)); +static int xbm_image_p P_ ((Lisp_Object object)); +static int xbm_read_bitmap_data P_ ((unsigned char *, unsigned char *, + int *, int *, unsigned char **)); +static int xbm_file_p P_ ((Lisp_Object)); + + +/* Indices of image specification fields in xbm_format, below. */ + +enum xbm_keyword_index +{ + XBM_TYPE, + XBM_FILE, + XBM_WIDTH, + XBM_HEIGHT, + XBM_DATA, + XBM_FOREGROUND, + XBM_BACKGROUND, + XBM_ASCENT, + XBM_MARGIN, + XBM_RELIEF, + XBM_ALGORITHM, + XBM_HEURISTIC_MASK, + XBM_MASK, + XBM_LAST +}; + +/* Vector of image_keyword structures describing the format + of valid XBM image specifications. */ + +static struct image_keyword xbm_format[XBM_LAST] = +{ + {":type", IMAGE_SYMBOL_VALUE, 1}, + {":file", IMAGE_STRING_VALUE, 0}, + {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0}, + {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 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_OR_PAIR, 0}, + {":relief", IMAGE_INTEGER_VALUE, 0}, + {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} +}; + +/* Structure describing the image type XBM. */ + +static struct image_type xbm_type = +{ + &Qxbm, + xbm_image_p, + xbm_load, + x_clear_image, + NULL +}; + +/* Tokens returned from xbm_scan. */ + +enum xbm_token +{ + XBM_TK_IDENT = 256, + XBM_TK_NUMBER +}; + + +/* Return non-zero if OBJECT is a valid XBM-type image specification. + A valid specification is a list starting with the symbol `image' + The rest of the list is a property list which must contain an + entry `:type xbm.. + + If the specification specifies a file to load, it must contain + an entry `:file FILENAME' where FILENAME is a string. + + If the specification is for a bitmap loaded from memory it must + contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where + WIDTH and HEIGHT are integers > 0. DATA may be: + + 1. a string large enough to hold the bitmap data, i.e. it must + have a size >= (WIDTH + 7) / 8 * HEIGHT + + 2. a bool-vector of size >= WIDTH * HEIGHT + + 3. a vector of strings or bool-vectors, one for each line of the + bitmap. + + 4. A string containing an in-memory XBM file. WIDTH and HEIGHT + may not be specified in this case because they are defined in the + XBM file. + + Both the file and data forms may contain the additional entries + `:background COLOR' and `:foreground COLOR'. If not present, + foreground and background of the frame on which the image is + displayed is used. */ + +static int +xbm_image_p (object) + Lisp_Object object; +{ + struct image_keyword kw[XBM_LAST]; + + bcopy (xbm_format, kw, sizeof kw); + if (!parse_image_spec (object, kw, XBM_LAST, Qxbm)) + return 0; + + xassert (EQ (kw[XBM_TYPE].value, Qxbm)); + + if (kw[XBM_FILE].count) + { + if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count) + return 0; + } + else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value)) + { + /* In-memory XBM file. */ + if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count) + return 0; + } + else + { + Lisp_Object data; + int width, height; + + /* Entries for `:width', `:height' and `:data' must be present. */ + if (!kw[XBM_WIDTH].count + || !kw[XBM_HEIGHT].count + || !kw[XBM_DATA].count) + return 0; + + data = kw[XBM_DATA].value; + width = XFASTINT (kw[XBM_WIDTH].value); + height = XFASTINT (kw[XBM_HEIGHT].value); + + /* Check type of data, and width and height against contents of + data. */ + if (VECTORP (data)) + { + int i; + + /* Number of elements of the vector must be >= height. */ + if (XVECTOR (data)->size < height) + return 0; + + /* Each string or bool-vector in data must be large enough + for one line of the image. */ + for (i = 0; i < height; ++i) + { + Lisp_Object elt = XVECTOR (data)->contents[i]; + + if (STRINGP (elt)) + { + if (SCHARS (elt) + < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR) + return 0; + } + else if (BOOL_VECTOR_P (elt)) + { + if (XBOOL_VECTOR (elt)->size < width) + return 0; + } + else + return 0; + } + } + else if (STRINGP (data)) + { + if (SCHARS (data) + < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height) + return 0; + } + else if (BOOL_VECTOR_P (data)) + { + if (XBOOL_VECTOR (data)->size < width * height) + return 0; + } + else + return 0; + } + + return 1; +} + + +/* Scan a bitmap file. FP is the stream to read from. Value is + either an enumerator from enum xbm_token, or a character for a + single-character token, or 0 at end of file. If scanning an + identifier, store the lexeme of the identifier in SVAL. If + scanning a number, store its value in *IVAL. */ + +static int +xbm_scan (s, end, sval, ival) + unsigned char **s, *end; + char *sval; + int *ival; +{ + unsigned int c; + + loop: + + /* Skip white space. */ + while (*s < end && (c = *(*s)++, isspace (c))) + ; + + if (*s >= end) + c = 0; + else if (isdigit (c)) + { + int value = 0, digit; + + if (c == '0' && *s < end) + { + c = *(*s)++; + if (c == 'x' || c == 'X') + { + while (*s < end) + { + c = *(*s)++; + if (isdigit (c)) + digit = c - '0'; + else if (c >= 'a' && c <= 'f') + digit = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + digit = c - 'A' + 10; + else + break; + value = 16 * value + digit; + } + } + else if (isdigit (c)) + { + value = c - '0'; + while (*s < end + && (c = *(*s)++, isdigit (c))) + value = 8 * value + c - '0'; + } + } + else + { + value = c - '0'; + while (*s < end + && (c = *(*s)++, isdigit (c))) + value = 10 * value + c - '0'; + } + + if (*s < end) + *s = *s - 1; + *ival = value; + c = XBM_TK_NUMBER; + } + else if (isalpha (c) || c == '_') + { + *sval++ = c; + while (*s < end + && (c = *(*s)++, (isalnum (c) || c == '_'))) + *sval++ = c; + *sval = 0; + if (*s < end) + *s = *s - 1; + c = XBM_TK_IDENT; + } + else if (c == '/' && **s == '*') + { + /* C-style comment. */ + ++*s; + while (**s && (**s != '*' || *(*s + 1) != '/')) + ++*s; + if (**s) + { + *s += 2; + goto loop; + } + } + + return c; +} + +#ifdef HAVE_NTGUI + +/* Create a Windows bitmap from X bitmap data. */ +static HBITMAP +w32_create_pixmap_from_bitmap_data (int width, int height, char *data) +{ + static unsigned char swap_nibble[16] + = { 0x0, 0x8, 0x4, 0xc, /* 0000 1000 0100 1100 */ + 0x2, 0xa, 0x6, 0xe, /* 0010 1010 0110 1110 */ + 0x1, 0x9, 0x5, 0xd, /* 0001 1001 0101 1101 */ + 0x3, 0xb, 0x7, 0xf }; /* 0011 1011 0111 1111 */ + int i, j, w1, w2; + unsigned char *bits, *p; + HBITMAP bmp; + + w1 = (width + 7) / 8; /* nb of 8bits elt in X bitmap */ + w2 = ((width + 15) / 16) * 2; /* nb of 16bits elt in W32 bitmap */ + bits = (unsigned char *) alloca (height * w2); + bzero (bits, height * w2); + for (i = 0; i < height; i++) + { + p = bits + i*w2; + for (j = 0; j < w1; j++) + { + /* Bitswap XBM bytes to match how Windows does things. */ + unsigned char c = *data++; + *p++ = (unsigned char)((swap_nibble[c & 0xf] << 4) + | (swap_nibble[(c>>4) & 0xf])); + } + } + bmp = CreateBitmap (width, height, 1, 1, (char *) bits); + + return bmp; +} + +static void convert_mono_to_color_image (f, img, foreground, background) + struct frame *f; + struct image *img; + COLORREF foreground, background; +{ + HDC hdc, old_img_dc, new_img_dc; + HGDIOBJ old_prev, new_prev; + HBITMAP new_pixmap; + + hdc = get_frame_dc (f); + old_img_dc = CreateCompatibleDC (hdc); + new_img_dc = CreateCompatibleDC (hdc); + new_pixmap = CreateCompatibleBitmap (hdc, img->width, img->height); + release_frame_dc (f, hdc); + old_prev = SelectObject (old_img_dc, img->pixmap); + new_prev = SelectObject (new_img_dc, new_pixmap); + SetTextColor (new_img_dc, foreground); + SetBkColor (new_img_dc, background); + + BitBlt (new_img_dc, 0, 0, img->width, img->height, old_img_dc, + 0, 0, SRCCOPY); + + SelectObject (old_img_dc, old_prev); + SelectObject (new_img_dc, new_prev); + DeleteDC (old_img_dc); + DeleteDC (new_img_dc); + DeleteObject (img->pixmap); + if (new_pixmap == 0) + fprintf (stderr, "Failed to convert image to color.\n"); + else + img->pixmap = new_pixmap; +} + +#define XBM_BIT_SHUFFLE(b) (~(b)) + +#else + +#define XBM_BIT_SHUFFLE(b) (b) + +#endif /* HAVE_NTGUI */ + + +static void +Create_Pixmap_From_Bitmap_Data(f, img, data, fg, bg, non_default_colors) + struct frame *f; + struct image *img; + char *data; + RGB_PIXEL_COLOR fg, bg; + int non_default_colors; +{ +#ifdef HAVE_NTGUI + img->pixmap + = w32_create_pixmap_from_bitmap_data (img->width, img->height, data); + + /* If colors were specified, transfer the bitmap to a color one. */ + if (non_default_colors) + convert_mono_to_color_image (f, img, fg, bg); +#else + img->pixmap + = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f), + FRAME_X_WINDOW (f), + data, + img->width, img->height, + fg, bg, + DefaultDepthOfScreen (FRAME_X_SCREEN (f))); +#endif /* HAVE_NTGUI */ +} + + + +/* Replacement for XReadBitmapFileData which isn't available under old + X versions. CONTENTS is a pointer to a buffer to parse; END is the + buffer's end. Set *WIDTH and *HEIGHT to the width and height of + the image. Return in *DATA the bitmap data allocated with xmalloc. + Value is non-zero if successful. DATA null means just test if + CONTENTS looks like an in-memory XBM file. */ + +static int +xbm_read_bitmap_data (contents, end, width, height, data) + unsigned char *contents, *end; + int *width, *height; + unsigned char **data; +{ + unsigned char *s = contents; + char buffer[BUFSIZ]; + int padding_p = 0; + int v10 = 0; + int bytes_per_line, i, nbytes; + unsigned char *p; + int value; + int LA1; + +#define match() \ + LA1 = xbm_scan (&s, end, buffer, &value) + +#define expect(TOKEN) \ + if (LA1 != (TOKEN)) \ + goto failure; \ + else \ + match () + +#define expect_ident(IDENT) \ + if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \ + match (); \ + else \ + goto failure + + *width = *height = -1; + if (data) + *data = NULL; + LA1 = xbm_scan (&s, end, buffer, &value); + + /* Parse defines for width, height and hot-spots. */ + while (LA1 == '#') + { + match (); + expect_ident ("define"); + expect (XBM_TK_IDENT); + + if (LA1 == XBM_TK_NUMBER); + { + char *p = strrchr (buffer, '_'); + p = p ? p + 1 : buffer; + if (strcmp (p, "width") == 0) + *width = value; + else if (strcmp (p, "height") == 0) + *height = value; + } + expect (XBM_TK_NUMBER); + } + + if (*width < 0 || *height < 0) + goto failure; + else if (data == NULL) + goto success; + + /* Parse bits. Must start with `static'. */ + expect_ident ("static"); + if (LA1 == XBM_TK_IDENT) + { + if (strcmp (buffer, "unsigned") == 0) + { + match (); + expect_ident ("char"); + } + else if (strcmp (buffer, "short") == 0) + { + match (); + v10 = 1; + if (*width % 16 && *width % 16 < 9) + padding_p = 1; + } + else if (strcmp (buffer, "char") == 0) + match (); + else + goto failure; + } + else + goto failure; + + expect (XBM_TK_IDENT); + expect ('['); + expect (']'); + expect ('='); + expect ('{'); + + bytes_per_line = (*width + 7) / 8 + padding_p; + nbytes = bytes_per_line * *height; + p = *data = (char *) xmalloc (nbytes); + + if (v10) + { + for (i = 0; i < nbytes; i += 2) + { + int val = value; + expect (XBM_TK_NUMBER); + + *p++ = XBM_BIT_SHUFFLE (val); + if (!padding_p || ((i + 2) % bytes_per_line)) + *p++ = XBM_BIT_SHUFFLE (value >> 8); + + if (LA1 == ',' || LA1 == '}') + match (); + else + goto failure; + } + } + else + { + for (i = 0; i < nbytes; ++i) + { + int val = value; + expect (XBM_TK_NUMBER); + + *p++ = XBM_BIT_SHUFFLE (val); + + if (LA1 == ',' || LA1 == '}') + match (); + else + goto failure; + } + } + + success: + return 1; + + failure: + + if (data && *data) + { + xfree (*data); + *data = NULL; + } + return 0; + +#undef match +#undef expect +#undef expect_ident +} + + +/* Load XBM image IMG which will be displayed on frame F from buffer + CONTENTS. END is the end of the buffer. Value is non-zero if + successful. */ + +static int +xbm_load_image (f, img, contents, end) + struct frame *f; + struct image *img; + unsigned char *contents, *end; +{ + int rc; + unsigned char *data; + int success_p = 0; + + rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data); + if (rc) + { + unsigned long foreground = FRAME_FOREGROUND_PIXEL (f); + unsigned long background = FRAME_BACKGROUND_PIXEL (f); + int non_default_colors = 0; + Lisp_Object value; + + xassert (img->width > 0 && img->height > 0); + + /* Get foreground and background colors, maybe allocate colors. */ + value = image_spec_value (img->spec, QCforeground, NULL); + if (!NILP (value)) + { + foreground = x_alloc_image_color (f, img, value, foreground); + non_default_colors = 1; + } + value = image_spec_value (img->spec, QCbackground, NULL); + if (!NILP (value)) + { + background = x_alloc_image_color (f, img, value, background); + img->background = background; + img->background_valid = 1; + non_default_colors = 1; + } + + Create_Pixmap_From_Bitmap_Data (f, img, data, + foreground, background, + non_default_colors); + xfree (data); + + if (img->pixmap == NO_PIXMAP) + { + x_clear_image (f, img); + image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil); + } + else + success_p = 1; + } + else + image_error ("Error loading XBM image `%s'", img->spec, Qnil); + + return success_p; +} + + +/* Value is non-zero if DATA looks like an in-memory XBM file. */ + +static int +xbm_file_p (data) + Lisp_Object data; +{ + int w, h; + return (STRINGP (data) + && xbm_read_bitmap_data (SDATA (data), + (SDATA (data) + + SBYTES (data)), + &w, &h, NULL)); +} + + +/* Fill image IMG which is used on frame F with pixmap data. Value is + non-zero if successful. */ + +static int +xbm_load (f, img) + struct frame *f; + struct image *img; +{ + int success_p = 0; + Lisp_Object file_name; + + xassert (xbm_image_p (img->spec)); + + /* If IMG->spec specifies a file name, create a non-file spec from it. */ + file_name = image_spec_value (img->spec, QCfile, NULL); + if (STRINGP (file_name)) + { + Lisp_Object file; + unsigned char *contents; + int size; + struct gcpro gcpro1; + + file = x_find_image_file (file_name); + GCPRO1 (file); + if (!STRINGP (file)) + { + image_error ("Cannot find image file `%s'", file_name, Qnil); + UNGCPRO; + return 0; + } + + contents = slurp_file (SDATA (file), &size); + if (contents == NULL) + { + image_error ("Error loading XBM image `%s'", img->spec, Qnil); + UNGCPRO; + return 0; + } + + success_p = xbm_load_image (f, img, contents, contents + size); + UNGCPRO; + } + else + { + struct image_keyword fmt[XBM_LAST]; + Lisp_Object data; + unsigned long foreground = FRAME_FOREGROUND_PIXEL (f); + unsigned long background = FRAME_BACKGROUND_PIXEL (f); + int non_default_colors = 0; + char *bits; + int parsed_p; + int in_memory_file_p = 0; + + /* See if data looks like an in-memory XBM file. */ + data = image_spec_value (img->spec, QCdata, NULL); + in_memory_file_p = xbm_file_p (data); + + /* Parse the image specification. */ + bcopy (xbm_format, fmt, sizeof fmt); + parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm); + xassert (parsed_p); + + /* Get specified width, and height. */ + if (!in_memory_file_p) + { + img->width = XFASTINT (fmt[XBM_WIDTH].value); + img->height = XFASTINT (fmt[XBM_HEIGHT].value); + xassert (img->width > 0 && img->height > 0); + } + + /* Get foreground and background colors, maybe allocate colors. */ + if (fmt[XBM_FOREGROUND].count + && STRINGP (fmt[XBM_FOREGROUND].value)) + { + foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value, + foreground); + non_default_colors = 1; + } + + if (fmt[XBM_BACKGROUND].count + && STRINGP (fmt[XBM_BACKGROUND].value)) + { + background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value, + background); + non_default_colors = 1; + } + + if (in_memory_file_p) + success_p = xbm_load_image (f, img, SDATA (data), + (SDATA (data) + + SBYTES (data))); + else + { + if (VECTORP (data)) + { + int i; + char *p; + int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR; + + p = bits = (char *) alloca (nbytes * img->height); + for (i = 0; i < img->height; ++i, p += nbytes) + { + Lisp_Object line = XVECTOR (data)->contents[i]; + if (STRINGP (line)) + bcopy (SDATA (line), p, nbytes); + else + bcopy (XBOOL_VECTOR (line)->data, p, nbytes); + } + } + else if (STRINGP (data)) + bits = SDATA (data); + else + bits = XBOOL_VECTOR (data)->data; + + /* Create the pixmap. */ + + Create_Pixmap_From_Bitmap_Data (f, img, bits, + foreground, background, + non_default_colors); + if (img->pixmap) + success_p = 1; + else + { + image_error ("Unable to create pixmap for XBM image `%s'", + img->spec, Qnil); + x_clear_image (f, img); + } + } + } + + return success_p; +} + + + +/*********************************************************************** + XPM images + ***********************************************************************/ + +#ifdef HAVE_XPM + +static int xpm_image_p P_ ((Lisp_Object object)); +static int xpm_load P_ ((struct frame *f, struct image *img)); +static int xpm_valid_color_symbols_p P_ ((Lisp_Object)); + +#ifdef HAVE_NTGUI +/* Indicate to xpm.h that we don't have Xlib. */ +#define FOR_MSW +/* simx.h in xpm defines XColor and XImage differently than Emacs. */ +#define XColor xpm_XColor +#define XImage xpm_XImage +#define PIXEL_ALREADY_TYPEDEFED +#include "X11/xpm.h" +#undef FOR_MSW +#undef XColor +#undef XImage +#undef PIXEL_ALREADY_TYPEDEFED +#else +#include "X11/xpm.h" +#endif /* HAVE_NTGUI */ + +/* The symbol `xpm' identifying XPM-format images. */ + +Lisp_Object Qxpm; + +/* Indices of image specification fields in xpm_format, below. */ + +enum xpm_keyword_index +{ + XPM_TYPE, + XPM_FILE, + XPM_DATA, + XPM_ASCENT, + XPM_MARGIN, + XPM_RELIEF, + XPM_ALGORITHM, + XPM_HEURISTIC_MASK, + XPM_MASK, + XPM_COLOR_SYMBOLS, + XPM_BACKGROUND, + XPM_LAST +}; + +/* Vector of image_keyword structures describing the format + of valid XPM image specifications. */ + +static struct image_keyword xpm_format[XPM_LAST] = +{ + {":type", IMAGE_SYMBOL_VALUE, 1}, + {":file", IMAGE_STRING_VALUE, 0}, + {":data", IMAGE_STRING_VALUE, 0}, + {":ascent", IMAGE_ASCENT_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, + {":relief", IMAGE_INTEGER_VALUE, 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}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} +}; + +/* Structure describing the image type XPM. */ + +static struct image_type xpm_type = +{ + &Qxpm, + xpm_image_p, + xpm_load, + x_clear_image, + NULL +}; + +#ifdef HAVE_X_WINDOWS + +/* Define ALLOC_XPM_COLORS if we can use Emacs' own color allocation + functions for allocating image colors. Our own functions handle + color allocation failures more gracefully than the ones on the XPM + lib. */ + +#if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure +#define ALLOC_XPM_COLORS +#endif +#endif /* HAVE_X_WINDOWS */ + +#ifdef ALLOC_XPM_COLORS + +static void xpm_init_color_cache P_ ((struct frame *, XpmAttributes *)); +static void xpm_free_color_cache P_ ((void)); +static int xpm_lookup_color P_ ((struct frame *, char *, XColor *)); +static int xpm_color_bucket P_ ((char *)); +static struct xpm_cached_color *xpm_cache_color P_ ((struct frame *, char *, + XColor *, int)); + +/* An entry in a hash table used to cache color definitions of named + colors. This cache is necessary to speed up XPM image loading in + case we do color allocations ourselves. Without it, we would need + a call to XParseColor per pixel in the image. */ + +struct xpm_cached_color +{ + /* Next in collision chain. */ + struct xpm_cached_color *next; + + /* Color definition (RGB and pixel color). */ + XColor color; + + /* Color name. */ + char name[1]; +}; + +/* The hash table used for the color cache, and its bucket vector + size. */ + +#define XPM_COLOR_CACHE_BUCKETS 1001 +struct xpm_cached_color **xpm_color_cache; + +/* Initialize the color cache. */ + +static void +xpm_init_color_cache (f, attrs) + struct frame *f; + XpmAttributes *attrs; +{ + size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache; + xpm_color_cache = (struct xpm_cached_color **) xmalloc (nbytes); + memset (xpm_color_cache, 0, nbytes); + init_color_table (); + + if (attrs->valuemask & XpmColorSymbols) + { + int i; + XColor color; + + for (i = 0; i < attrs->numsymbols; ++i) + if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), + attrs->colorsymbols[i].value, &color)) + { + color.pixel = lookup_rgb_color (f, color.red, color.green, + color.blue); + xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1); + } + } +} + +/* Free the color cache. */ + +static void +xpm_free_color_cache () +{ + struct xpm_cached_color *p, *next; + int i; + + for (i = 0; i < XPM_COLOR_CACHE_BUCKETS; ++i) + for (p = xpm_color_cache[i]; p; p = next) + { + next = p->next; + xfree (p); + } + + xfree (xpm_color_cache); + xpm_color_cache = NULL; + free_color_table (); +} + +/* Return the bucket index for color named COLOR_NAME in the color + cache. */ + +static int +xpm_color_bucket (color_name) + char *color_name; +{ + unsigned h = 0; + char *s; + + for (s = color_name; *s; ++s) + h = (h << 2) ^ *s; + return h %= XPM_COLOR_CACHE_BUCKETS; +} + + +/* On frame F, cache values COLOR for color with name COLOR_NAME. + BUCKET, if >= 0, is a precomputed bucket index. Value is the cache + entry added. */ + +static struct xpm_cached_color * +xpm_cache_color (f, color_name, color, bucket) + struct frame *f; + char *color_name; + XColor *color; + int bucket; +{ + size_t nbytes; + struct xpm_cached_color *p; + + if (bucket < 0) + bucket = xpm_color_bucket (color_name); + + nbytes = sizeof *p + strlen (color_name); + p = (struct xpm_cached_color *) xmalloc (nbytes); + strcpy (p->name, color_name); + p->color = *color; + p->next = xpm_color_cache[bucket]; + xpm_color_cache[bucket] = p; + return p; +} + +/* Look up color COLOR_NAME for frame F in the color cache. If found, + return the cached definition in *COLOR. Otherwise, make a new + entry in the cache and allocate the color. Value is zero if color + allocation failed. */ + +static int +xpm_lookup_color (f, color_name, color) + struct frame *f; + char *color_name; + XColor *color; +{ + struct xpm_cached_color *p; + int h = xpm_color_bucket (color_name); + + for (p = xpm_color_cache[h]; p; p = p->next) + if (strcmp (p->name, color_name) == 0) + break; + + if (p != NULL) + *color = p->color; + else if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), + color_name, color)) + { + color->pixel = lookup_rgb_color (f, color->red, color->green, + color->blue); + p = xpm_cache_color (f, color_name, color, h); + } + /* You get `opaque' at least from ImageMagick converting pbm to xpm + with transparency, and it's useful. */ + else if (strcmp ("opaque", color_name) == 0) + { + bzero (color, sizeof (XColor)); /* Is this necessary/correct? */ + color->pixel = FRAME_FOREGROUND_PIXEL (f); + p = xpm_cache_color (f, color_name, color, h); + } + + return p != NULL; +} + + +/* Callback for allocating color COLOR_NAME. Called from the XPM lib. + CLOSURE is a pointer to the frame on which we allocate the + color. Return in *COLOR the allocated color. Value is non-zero + if successful. */ + +static int +xpm_alloc_color (dpy, cmap, color_name, color, closure) + Display *dpy; + Colormap cmap; + char *color_name; + XColor *color; + void *closure; +{ + return xpm_lookup_color ((struct frame *) closure, color_name, color); +} + + +/* Callback for freeing NPIXELS colors contained in PIXELS. CLOSURE + is a pointer to the frame on which we allocate the color. Value is + non-zero if successful. */ + +static int +xpm_free_colors (dpy, cmap, pixels, npixels, closure) + Display *dpy; + Colormap cmap; + Pixel *pixels; + int npixels; + void *closure; +{ + return 1; +} + +#endif /* ALLOC_XPM_COLORS */ + + +#ifdef HAVE_NTGUI + +/* XPM library details. */ + +DEF_IMGLIB_FN (XpmFreeAttributes); +DEF_IMGLIB_FN (XpmCreateImageFromBuffer); +DEF_IMGLIB_FN (XpmReadFileToImage); +DEF_IMGLIB_FN (XImageFree); + + +static int +init_xpm_functions (void) +{ + HMODULE library; + + if (!(library = LoadLibrary ("libXpm.dll"))) + return 0; + + LOAD_IMGLIB_FN (library, XpmFreeAttributes); + LOAD_IMGLIB_FN (library, XpmCreateImageFromBuffer); + LOAD_IMGLIB_FN (library, XpmReadFileToImage); + LOAD_IMGLIB_FN (library, XImageFree); + return 1; +} + +#endif /* HAVE_NTGUI */ + + +/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list + for XPM images. Such a list must consist of conses whose car and + cdr are strings. */ + +static int +xpm_valid_color_symbols_p (color_symbols) + Lisp_Object color_symbols; +{ + while (CONSP (color_symbols)) + { + Lisp_Object sym = XCAR (color_symbols); + if (!CONSP (sym) + || !STRINGP (XCAR (sym)) + || !STRINGP (XCDR (sym))) + break; + color_symbols = XCDR (color_symbols); + } + + return NILP (color_symbols); +} + + +/* Value is non-zero if OBJECT is a valid XPM image specification. */ + +static int +xpm_image_p (object) + Lisp_Object object; +{ + struct image_keyword fmt[XPM_LAST]; + bcopy (xpm_format, fmt, sizeof fmt); + return (parse_image_spec (object, fmt, XPM_LAST, Qxpm) + /* Either `:file' or `:data' must be present. */ + && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1 + /* Either no `:color-symbols' or it's a list of conses + whose car and cdr are strings. */ + && (fmt[XPM_COLOR_SYMBOLS].count == 0 + || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))); +} + + +/* Load image IMG which will be displayed on frame F. Value is + non-zero if successful. */ + +static int +xpm_load (f, img) + struct frame *f; + struct image *img; +{ + int rc; + XpmAttributes attrs; + Lisp_Object specified_file, color_symbols; +#ifdef HAVE_NTGUI + HDC hdc; + xpm_XImage * xpm_image = NULL, * xpm_mask = NULL; +#endif /* HAVE_NTGUI */ + + /* Configure the XPM lib. Use the visual of frame F. Allocate + close colors. Return colors allocated. */ + bzero (&attrs, sizeof attrs); + +#ifndef HAVE_NTGUI + attrs.visual = FRAME_X_VISUAL (f); + attrs.colormap = FRAME_X_COLORMAP (f); + attrs.valuemask |= XpmVisual; + attrs.valuemask |= XpmColormap; +#endif /* HAVE_NTGUI */ + +#ifdef ALLOC_XPM_COLORS + /* Allocate colors with our own functions which handle + failing color allocation more gracefully. */ + attrs.color_closure = f; + attrs.alloc_color = xpm_alloc_color; + attrs.free_colors = xpm_free_colors; + attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure; +#else /* not ALLOC_XPM_COLORS */ + /* Let the XPM lib allocate colors. */ + attrs.valuemask |= XpmReturnAllocPixels; +#ifdef XpmAllocCloseColors + attrs.alloc_close_colors = 1; + attrs.valuemask |= XpmAllocCloseColors; +#else /* not XpmAllocCloseColors */ + attrs.closeness = 600; + attrs.valuemask |= XpmCloseness; +#endif /* not XpmAllocCloseColors */ +#endif /* ALLOC_XPM_COLORS */ + + /* If image specification contains symbolic color definitions, add + these to `attrs'. */ + color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL); + if (CONSP (color_symbols)) + { + Lisp_Object tail; + XpmColorSymbol *xpm_syms; + int i, size; + + attrs.valuemask |= XpmColorSymbols; + + /* Count number of symbols. */ + attrs.numsymbols = 0; + for (tail = color_symbols; CONSP (tail); tail = XCDR (tail)) + ++attrs.numsymbols; + + /* Allocate an XpmColorSymbol array. */ + size = attrs.numsymbols * sizeof *xpm_syms; + xpm_syms = (XpmColorSymbol *) alloca (size); + bzero (xpm_syms, size); + attrs.colorsymbols = xpm_syms; + + /* Fill the color symbol array. */ + for (tail = color_symbols, i = 0; + CONSP (tail); + ++i, tail = XCDR (tail)) + { + Lisp_Object name = XCAR (XCAR (tail)); + Lisp_Object color = XCDR (XCAR (tail)); + xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1); + strcpy (xpm_syms[i].name, SDATA (name)); + xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1); + strcpy (xpm_syms[i].value, SDATA (color)); + } + } + + /* Create a pixmap for the image, either from a file, or from a + string buffer containing data in the same format as an XPM file. */ +#ifdef ALLOC_XPM_COLORS + xpm_init_color_cache (f, &attrs); +#endif + + specified_file = image_spec_value (img->spec, QCfile, NULL); + +#ifdef HAVE_NTGUI + { + HDC frame_dc = get_frame_dc (f); + hdc = CreateCompatibleDC (frame_dc); + release_frame_dc (f, frame_dc); + } +#endif /* HAVE_NTGUI */ + + if (STRINGP (specified_file)) + { + Lisp_Object file = x_find_image_file (specified_file); + if (!STRINGP (file)) + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + return 0; + } + +#ifdef HAVE_NTGUI + /* XpmReadFileToPixmap is not available in the Windows port of + libxpm. But XpmReadFileToImage almost does what we want. */ + rc = fn_XpmReadFileToImage (&hdc, SDATA (file), + &xpm_image, &xpm_mask, + &attrs); +#else + rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + SDATA (file), &img->pixmap, &img->mask, + &attrs); +#endif /* HAVE_NTGUI */ + } + else + { + Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL); +#ifdef HAVE_NTGUI + /* XpmCreatePixmapFromBuffer is not available in the Windows port + of libxpm. But XpmCreateImageFromBuffer almost does what we want. */ + rc = fn_XpmCreateImageFromBuffer (&hdc, SDATA (buffer), + &xpm_image, &xpm_mask, + &attrs); +#else + rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + SDATA (buffer), + &img->pixmap, &img->mask, + &attrs); +#endif /* HAVE_NTGUI */ + } + + if (rc == XpmSuccess) + { +#if defined (COLOR_TABLE_SUPPORT) && defined (ALLOC_XPM_COLORS) + img->colors = colors_in_color_table (&img->ncolors); +#else /* not ALLOC_XPM_COLORS */ + int i; + +#ifdef HAVE_NTGUI + /* W32 XPM uses XImage to wrap what W32 Emacs calls a Pixmap, + plus some duplicate attributes. */ + if (xpm_image && xpm_image->bitmap) + { + img->pixmap = xpm_image->bitmap; + /* XImageFree in libXpm frees XImage struct without destroying + the bitmap, which is what we want. */ + fn_XImageFree (xpm_image); + } + if (xpm_mask && xpm_mask->bitmap) + { + /* The mask appears to be inverted compared with what we expect. + TODO: invert our expectations. See other places where we + have to invert bits because our idea of masks is backwards. */ + HGDIOBJ old_obj; + old_obj = SelectObject (hdc, xpm_mask->bitmap); + + PatBlt (hdc, 0, 0, xpm_mask->width, xpm_mask->height, DSTINVERT); + SelectObject (hdc, old_obj); + + img->mask = xpm_mask->bitmap; + fn_XImageFree (xpm_mask); + DeleteDC (hdc); + } + + DeleteDC (hdc); +#endif /* HAVE_NTGUI */ + + /* Remember allocated colors. */ + img->ncolors = attrs.nalloc_pixels; + img->colors = (unsigned long *) xmalloc (img->ncolors + * sizeof *img->colors); + for (i = 0; i < attrs.nalloc_pixels; ++i) + { + img->colors[i] = attrs.alloc_pixels[i]; +#ifdef DEBUG_X_COLORS + register_color (img->colors[i]); +#endif + } +#endif /* not ALLOC_XPM_COLORS */ + + img->width = attrs.width; + img->height = attrs.height; + xassert (img->width > 0 && img->height > 0); + + /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */ +#ifdef HAVE_NTGUI + fn_XpmFreeAttributes (&attrs); +#else + XpmFreeAttributes (&attrs); +#endif /* HAVE_NTGUI */ + } + else + { +#ifdef HAVE_NTGUI + DeleteDC (hdc); +#endif /* HAVE_NTGUI */ + + switch (rc) + { + case XpmOpenFailed: + image_error ("Error opening XPM file (%s)", img->spec, Qnil); + break; + + case XpmFileInvalid: + image_error ("Invalid XPM file (%s)", img->spec, Qnil); + break; + + case XpmNoMemory: + image_error ("Out of memory (%s)", img->spec, Qnil); + break; + + case XpmColorFailed: + image_error ("Color allocation error (%s)", img->spec, Qnil); + break; + + default: + image_error ("Unknown error (%s)", img->spec, Qnil); + break; + } + } + +#ifdef ALLOC_XPM_COLORS + xpm_free_color_cache (); +#endif + return rc == XpmSuccess; +} + +#endif /* HAVE_XPM */ + + +/*********************************************************************** + Color table + ***********************************************************************/ + +#ifdef COLOR_TABLE_SUPPORT + +/* An entry in the color table mapping an RGB color to a pixel color. */ + +struct ct_color +{ + int r, g, b; + unsigned long pixel; + + /* Next in color table collision list. */ + struct ct_color *next; +}; + +/* The bucket vector size to use. Must be prime. */ + +#define CT_SIZE 101 + +/* Value is a hash of the RGB color given by R, G, and B. */ + +#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B)) + +/* The color hash table. */ + +struct ct_color **ct_table; + +/* Number of entries in the color table. */ + +int ct_colors_allocated; + +/* Initialize the color table. */ + +static void +init_color_table () +{ + int size = CT_SIZE * sizeof (*ct_table); + ct_table = (struct ct_color **) xmalloc (size); + bzero (ct_table, size); + ct_colors_allocated = 0; +} + + +/* Free memory associated with the color table. */ + +static void +free_color_table () +{ + int i; + struct ct_color *p, *next; + + for (i = 0; i < CT_SIZE; ++i) + for (p = ct_table[i]; p; p = next) + { + next = p->next; + xfree (p); + } + + xfree (ct_table); + ct_table = NULL; +} + + +/* Value is a pixel color for RGB color R, G, B on frame F. If an + entry for that color already is in the color table, return the + pixel color of that entry. Otherwise, allocate a new color for R, + G, B, and make an entry in the color table. */ + +static unsigned long +lookup_rgb_color (f, r, g, b) + struct frame *f; + int r, g, b; +{ + unsigned hash = CT_HASH_RGB (r, g, b); + int i = hash % CT_SIZE; + struct ct_color *p; + Display_Info *dpyinfo; + + /* Handle TrueColor visuals specially, which improves performance by + two orders of magnitude. Freeing colors on TrueColor visuals is + a nop, and pixel colors specify RGB values directly. See also + the Xlib spec, chapter 3.1. */ + dpyinfo = FRAME_X_DISPLAY_INFO (f); + if (dpyinfo->red_bits > 0) + { + unsigned long pr, pg, pb; + + /* Apply gamma-correction like normal color allocation does. */ + if (f->gamma) + { + XColor color; + color.red = r, color.green = g, color.blue = b; + gamma_correct (f, &color); + r = color.red, g = color.green, b = color.blue; + } + + /* Scale down RGB values to the visual's bits per RGB, and shift + them to the right position in the pixel color. Note that the + original RGB values are 16-bit values, as usual in X. */ + pr = (r >> (16 - dpyinfo->red_bits)) << dpyinfo->red_offset; + pg = (g >> (16 - dpyinfo->green_bits)) << dpyinfo->green_offset; + pb = (b >> (16 - dpyinfo->blue_bits)) << dpyinfo->blue_offset; + + /* Assemble the pixel color. */ + return pr | pg | pb; + } + + for (p = ct_table[i]; p; p = p->next) + if (p->r == r && p->g == g && p->b == b) + break; + + if (p == NULL) + { + +#ifdef HAVE_X_WINDOWS + XColor color; + Colormap cmap; + int rc; + + color.red = r; + color.green = g; + color.blue = b; + + cmap = FRAME_X_COLORMAP (f); + rc = x_alloc_nearest_color (f, cmap, &color); + if (rc) + { + ++ct_colors_allocated; + p = (struct ct_color *) xmalloc (sizeof *p); + p->r = r; + p->g = g; + p->b = b; + p->pixel = color.pixel; + p->next = ct_table[i]; + ct_table[i] = p; + } + else + return FRAME_FOREGROUND_PIXEL (f); + +#else + COLORREF color; +#ifdef HAVE_NTGUI + color = PALETTERGB (r, g, b); +#else + color = RGB_TO_ULONG (r, g, b); +#endif /* HAVE_NTGUI */ + ++ct_colors_allocated; + p = (struct ct_color *) xmalloc (sizeof *p); + p->r = r; + p->g = g; + p->b = b; + p->pixel = color; + p->next = ct_table[i]; + ct_table[i] = p; +#endif /* HAVE_X_WINDOWS */ + + } + + return p->pixel; +} + + +/* Look up pixel color PIXEL which is used on frame F in the color + table. If not already present, allocate it. Value is PIXEL. */ + +static unsigned long +lookup_pixel_color (f, pixel) + struct frame *f; + unsigned long pixel; +{ + int i = pixel % CT_SIZE; + struct ct_color *p; + + for (p = ct_table[i]; p; p = p->next) + if (p->pixel == pixel) + break; + + if (p == NULL) + { + XColor color; + Colormap cmap; + int rc; + +#ifdef HAVE_X_WINDOWS + cmap = FRAME_X_COLORMAP (f); + color.pixel = pixel; + x_query_color (f, &color); + rc = x_alloc_nearest_color (f, cmap, &color); +#else + BLOCK_INPUT; + cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); + color.pixel = pixel; + XQueryColor (NULL, cmap, &color); + rc = x_alloc_nearest_color (f, cmap, &color); + UNBLOCK_INPUT; +#endif /* HAVE_X_WINDOWS */ + + if (rc) + { + ++ct_colors_allocated; + + p = (struct ct_color *) xmalloc (sizeof *p); + p->r = color.red; + p->g = color.green; + p->b = color.blue; + p->pixel = pixel; + p->next = ct_table[i]; + ct_table[i] = p; + } + else + return FRAME_FOREGROUND_PIXEL (f); + } + return p->pixel; +} + + +/* Value is a vector of all pixel colors contained in the color table, + allocated via xmalloc. Set *N to the number of colors. */ + +static unsigned long * +colors_in_color_table (n) + int *n; +{ + int i, j; + struct ct_color *p; + unsigned long *colors; + + if (ct_colors_allocated == 0) + { + *n = 0; + colors = NULL; + } + else + { + colors = (unsigned long *) xmalloc (ct_colors_allocated + * sizeof *colors); + *n = ct_colors_allocated; + + for (i = j = 0; i < CT_SIZE; ++i) + for (p = ct_table[i]; p; p = p->next) + colors[j++] = p->pixel; + } + + return colors; +} + +#else /* COLOR_TABLE_SUPPORT */ + +static unsigned long +lookup_rgb_color (f, r, g, b) + struct frame *f; + int r, g, b; +{ + unsigned long pixel; + +#ifdef MAC_OS + pixel = RGB_TO_ULONG (r >> 8, g >> 8, b >> 8); + gamma_correct (f, &pixel); +#endif /* MAC_OS */ + +#ifdef HAVE_NTGUI + pixel = PALETTERGB (r >> 8, g >> 8, b >> 8); +#endif /* HAVE_NTGUI */ + + return pixel; +} + +static void +init_color_table () +{ +} +#endif /* COLOR_TABLE_SUPPORT */ + + +/*********************************************************************** + Algorithms + ***********************************************************************/ + +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)); + +#ifdef HAVE_NTGUI +static void XPutPixel (XImagePtr , int, int, COLORREF); +#endif /* HAVE_NTGUI */ + +/* Non-zero means draw a cross on images having `:conversion + disabled'. */ + +int cross_disabled_images; + +/* Edge detection matrices for different edge-detection + strategies. */ + +static int emboss_matrix[9] = { + /* x - 1 x x + 1 */ + 2, -1, 0, /* y - 1 */ + -1, 0, 1, /* y */ + 0, 1, -2 /* y + 1 */ +}; + +static int laplace_matrix[9] = { + /* x - 1 x x + 1 */ + 1, 0, 0, /* y - 1 */ + 0, 0, 0, /* y */ + 0, 0, -1 /* y + 1 */ +}; + +/* Value is the intensity of the color whose red/green/blue values + are R, G, and B. */ + +#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6) + + +/* On frame F, return an array of XColor structures describing image + IMG->pixmap. Each XColor structure has its pixel color set. RGB_P + non-zero means also fill the red/green/blue members of the XColor + structures. Value is a pointer to the array of XColors structures, + allocated with xmalloc; it must be freed by the caller. */ + +static XColor * +x_to_xcolors (f, img, rgb_p) + struct frame *f; + struct image *img; + int rgb_p; +{ + int x, y; + XColor *colors, *p; + XImagePtr_or_DC ximg; +#ifdef HAVE_NTGUI + HDC hdc; + HGDIOBJ prev; +#endif /* HAVE_NTGUI */ + + colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors); + +#ifndef HAVE_NTGUI + /* Get the X image IMG->pixmap. */ + ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap, + 0, 0, img->width, img->height, ~0, ZPixmap); +#else + /* Load the image into a memory device context. */ + hdc = get_frame_dc (f); + ximg = CreateCompatibleDC (hdc); + release_frame_dc (f, hdc); + prev = SelectObject (ximg, img->pixmap); +#endif /* HAVE_NTGUI */ + + /* Fill the `pixel' members of the XColor array. I wished there + were an easy and portable way to circumvent XGetPixel. */ + p = colors; + for (y = 0; y < img->height; ++y) + { + XColor *row = p; + +#ifdef HAVE_X_WINDOWS + for (x = 0; x < img->width; ++x, ++p) + p->pixel = XGetPixel (ximg, x, y); + if (rgb_p) + x_query_colors (f, row, img->width); + +#else + + for (x = 0; x < img->width; ++x, ++p) + { + /* W32_TODO: palette support needed here? */ + p->pixel = GET_PIXEL (ximg, x, y); + if (rgb_p) + { +#ifdef MAC_OS + p->red = RED16_FROM_ULONG (p->pixel); + p->green = GREEN16_FROM_ULONG (p->pixel); + p->blue = BLUE16_FROM_ULONG (p->pixel); +#endif /* MAC_OS */ +#ifdef HAVE_NTGUI + p->red = 256 * GetRValue (p->pixel); + p->green = 256 * GetGValue (p->pixel); + p->blue = 256 * GetBValue (p->pixel); +#endif /* HAVE_NTGUI */ + } + } +#endif /* HAVE_X_WINDOWS */ + } + + Destroy_Image (ximg, prev); + + return colors; +} + +#ifdef HAVE_NTGUI + +/* Put a pixel of COLOR at position X, Y in XIMG. XIMG must have been + created with CreateDIBSection, with the pointer to the bit values + stored in ximg->data. */ + +static void XPutPixel (ximg, x, y, color) + XImagePtr ximg; + int x, y; + COLORREF color; +{ + int width = ximg->info.bmiHeader.biWidth; + int height = ximg->info.bmiHeader.biHeight; + unsigned char * pixel; + + /* True color images. */ + if (ximg->info.bmiHeader.biBitCount == 24) + { + int rowbytes = width * 3; + /* Ensure scanlines are aligned on 4 byte boundaries. */ + if (rowbytes % 4) + rowbytes += 4 - (rowbytes % 4); + + pixel = ximg->data + y * rowbytes + x * 3; + /* Windows bitmaps are in BGR order. */ + *pixel = GetBValue (color); + *(pixel + 1) = GetGValue (color); + *(pixel + 2) = GetRValue (color); + } + /* Monochrome images. */ + else if (ximg->info.bmiHeader.biBitCount == 1) + { + int rowbytes = width / 8; + /* Ensure scanlines are aligned on 4 byte boundaries. */ + if (rowbytes % 4) + rowbytes += 4 - (rowbytes % 4); + pixel = ximg->data + y * rowbytes + x / 8; + /* Filter out palette info. */ + if (color & 0x00ffffff) + *pixel = *pixel | (1 << x % 8); + else + *pixel = *pixel & ~(1 << x % 8); + } + else + image_error ("XPutPixel: palette image not supported", Qnil, Qnil); +} + +#endif /* HAVE_NTGUI */ + +/* Create IMG->pixmap from an array COLORS of XColor structures, whose + RGB members are set. F is the frame on which this all happens. + COLORS will be freed; an existing IMG->pixmap will be freed, too. */ + +static void +x_from_xcolors (f, img, colors) + struct frame *f; + struct image *img; + XColor *colors; +{ + int x, y; + XImagePtr oimg; + Pixmap pixmap; + XColor *p; + + init_color_table (); + + x_create_x_image_and_pixmap (f, img->width, img->height, 0, + &oimg, &pixmap); + p = colors; + for (y = 0; y < img->height; ++y) + for (x = 0; x < img->width; ++x, ++p) + { + unsigned long pixel; + pixel = lookup_rgb_color (f, p->red, p->green, p->blue); + XPutPixel (oimg, x, y, pixel); + } + + xfree (colors); + x_clear_image_1 (f, img, 1, 0, 1); + + x_put_x_image (f, oimg, pixmap, img->width, img->height); + x_destroy_x_image (oimg); + img->pixmap = pixmap; +#ifdef COLOR_TABLE_SUPPORT + img->colors = colors_in_color_table (&img->ncolors); + free_color_table (); +#endif /* COLOR_TABLE_SUPPORT */ +} + + +/* On frame F, perform edge-detection on image IMG. + + MATRIX is a nine-element array specifying the transformation + matrix. See emboss_matrix for an example. + + COLOR_ADJUST is a color adjustment added to each pixel of the + outgoing image. */ + +static void +x_detect_edges (f, img, matrix, color_adjust) + struct frame *f; + struct image *img; + int matrix[9], color_adjust; +{ + XColor *colors = x_to_xcolors (f, img, 1); + XColor *new, *p; + int x, y, i, sum; + + for (i = sum = 0; i < 9; ++i) + sum += abs (matrix[i]); + +#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X)) + + new = (XColor *) xmalloc (img->width * img->height * sizeof *new); + + for (y = 0; y < img->height; ++y) + { + p = COLOR (new, 0, y); + p->red = p->green = p->blue = 0xffff/2; + p = COLOR (new, img->width - 1, y); + p->red = p->green = p->blue = 0xffff/2; + } + + for (x = 1; x < img->width - 1; ++x) + { + p = COLOR (new, x, 0); + p->red = p->green = p->blue = 0xffff/2; + p = COLOR (new, x, img->height - 1); + p->red = p->green = p->blue = 0xffff/2; + } + + for (y = 1; y < img->height - 1; ++y) + { + p = COLOR (new, 1, y); + + for (x = 1; x < img->width - 1; ++x, ++p) + { + int r, g, b, y1, x1; + + r = g = b = i = 0; + for (y1 = y - 1; y1 < y + 2; ++y1) + for (x1 = x - 1; x1 < x + 2; ++x1, ++i) + if (matrix[i]) + { + XColor *t = COLOR (colors, x1, y1); + r += matrix[i] * t->red; + g += matrix[i] * t->green; + b += matrix[i] * t->blue; + } + + r = (r / sum + color_adjust) & 0xffff; + g = (g / sum + color_adjust) & 0xffff; + b = (b / sum + color_adjust) & 0xffff; + p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b); + } + } + + xfree (colors); + x_from_xcolors (f, img, new); + +#undef COLOR +} + + +/* Perform the pre-defined `emboss' edge-detection on image IMG + on frame F. */ + +static void +x_emboss (f, img) + struct frame *f; + struct image *img; +{ + x_detect_edges (f, img, emboss_matrix, 0xffff / 2); +} + + +/* Transform image IMG which is used on frame F with a Laplace + edge-detection algorithm. The result is an image that can be used + to draw disabled buttons, for example. */ + +static void +x_laplace (f, img) + struct frame *f; + struct image *img; +{ + x_detect_edges (f, img, laplace_matrix, 45000); +} + + +/* Perform edge-detection on image IMG on frame F, with specified + transformation matrix MATRIX and color-adjustment COLOR_ADJUST. + + MATRIX must be either + + - a list of at least 9 numbers in row-major form + - a vector of at least 9 numbers + + COLOR_ADJUST nil means use a default; otherwise it must be a + number. */ + +static void +x_edge_detection (f, img, matrix, color_adjust) + struct frame *f; + struct image *img; + Lisp_Object matrix, color_adjust; +{ + int i = 0; + int trans[9]; + + if (CONSP (matrix)) + { + for (i = 0; + i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix)); + ++i, matrix = XCDR (matrix)) + trans[i] = XFLOATINT (XCAR (matrix)); + } + else if (VECTORP (matrix) && ASIZE (matrix) >= 9) + { + for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i) + trans[i] = XFLOATINT (AREF (matrix, i)); + } + + if (NILP (color_adjust)) + color_adjust = make_number (0xffff / 2); + + if (i == 9 && NUMBERP (color_adjust)) + x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust)); +} + + +/* Transform image IMG on frame F so that it looks disabled. */ + +static void +x_disable_image (f, img) + struct frame *f; + struct image *img; +{ + Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); +#ifdef HAVE_NTGUI + int n_planes = dpyinfo->n_planes * dpyinfo->n_cbits; +#else + int n_planes = dpyinfo->n_planes; +#endif /* HAVE_NTGUI */ + + if (n_planes >= 2) + { + /* Color (or grayscale). Convert to gray, and equalize. Just + drawing such images with a stipple can look very odd, so + we're using this method instead. */ + XColor *colors = x_to_xcolors (f, img, 1); + XColor *p, *end; + const int h = 15000; + const int l = 30000; + + for (p = colors, end = colors + img->width * img->height; + p < end; + ++p) + { + int i = COLOR_INTENSITY (p->red, p->green, p->blue); + int i2 = (0xffff - h - l) * i / 0xffff + l; + p->red = p->green = p->blue = i2; + } + + x_from_xcolors (f, img, colors); + } + + /* Draw a cross over the disabled image, if we must or if we + should. */ + if (n_planes < 2 || cross_disabled_images) + { +#ifndef HAVE_NTGUI + Display *dpy = FRAME_X_DISPLAY (f); + GC gc; + +#ifdef MAC_OS +#define XCreateGC_pixmap(dpy, pixmap) XCreateGC (dpy, NULL, 0, NULL) +#define MaskForeground(f) PIX_MASK_DRAW (f) +#else +#define XCreateGC_pixmap(dpy, pixmap) XCreateGC (dpy, pixmap, 0, NULL) +#define MaskForeground(f) WHITE_PIX_DEFAULT (f) +#endif + + gc = XCreateGC_pixmap (dpy, img->pixmap); + XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f)); + XDrawLine (dpy, img->pixmap, gc, 0, 0, + img->width - 1, img->height - 1); + XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1, + img->width - 1, 0); + XFreeGC (dpy, gc); + + if (img->mask) + { + gc = XCreateGC_pixmap (dpy, img->mask); + XSetForeground (dpy, gc, MaskForeground (f)); + XDrawLine (dpy, img->mask, gc, 0, 0, + img->width - 1, img->height - 1); + XDrawLine (dpy, img->mask, gc, 0, img->height - 1, + img->width - 1, 0); + XFreeGC (dpy, gc); + } +#else + HDC hdc, bmpdc; + HGDIOBJ prev; + + hdc = get_frame_dc (f); + bmpdc = CreateCompatibleDC (hdc); + release_frame_dc (f, hdc); + + prev = SelectObject (bmpdc, img->pixmap); + + SetTextColor (bmpdc, BLACK_PIX_DEFAULT (f)); + MoveToEx (bmpdc, 0, 0, NULL); + LineTo (bmpdc, img->width - 1, img->height - 1); + MoveToEx (bmpdc, 0, img->height - 1, NULL); + LineTo (bmpdc, img->width - 1, 0); + + if (img->mask) + { + SelectObject (bmpdc, img->mask); + SetTextColor (bmpdc, WHITE_PIX_DEFAULT (f)); + MoveToEx (bmpdc, 0, 0, NULL); + LineTo (bmpdc, img->width - 1, img->height - 1); + MoveToEx (bmpdc, 0, img->height - 1, NULL); + LineTo (bmpdc, img->width - 1, 0); + } + SelectObject (bmpdc, prev); + DeleteDC (bmpdc); +#endif /* HAVE_NTGUI */ + } +} + + +/* Build a mask for image IMG which is used on frame F. FILE is the + name of an image file, for error messages. HOW determines how to + determine the background color of IMG. If it is a list '(R G B)', + with R, G, and B being integers >= 0, take that as the color of the + background. Otherwise, determine the background color of IMG + heuristically. Value is non-zero if successful. */ + +static int +x_build_heuristic_mask (f, img, how) + struct frame *f; + struct image *img; + Lisp_Object how; +{ + XImagePtr_or_DC ximg; +#ifndef HAVE_NTGUI + XImagePtr mask_img; +#else + HDC frame_dc; + HGDIOBJ prev; + char *mask_img; + int row_width; +#endif /* HAVE_NTGUI */ + int x, y, rc, use_img_background; + unsigned long bg = 0; + + if (img->mask) + { + Free_Pixmap (FRAME_X_DISPLAY (f), img->mask); + img->mask = NO_PIXMAP; + img->background_transparent_valid = 0; + } + +#ifndef HAVE_NTGUI + /* Create an image and pixmap serving as mask. */ + rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1, + &mask_img, &img->mask); + if (!rc) + return 0; + + /* Get the X image of IMG->pixmap. */ + ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap, 0, 0, + img->width, img->height, + ~0, ZPixmap); +#else + /* Create the bit array serving as mask. */ + row_width = (img->width + 7) / 8; + mask_img = xmalloc (row_width * img->height); + bzero (mask_img, row_width * img->height); + + /* Create a memory device context for IMG->pixmap. */ + frame_dc = get_frame_dc (f); + ximg = CreateCompatibleDC (frame_dc); + release_frame_dc (f, frame_dc); + prev = SelectObject (ximg, img->pixmap); +#endif /* HAVE_NTGUI */ + + /* Determine the background color of ximg. If HOW is `(R G B)' + take that as color. Otherwise, use the image's background color. */ + use_img_background = 1; + + if (CONSP (how)) + { + int rgb[3], i; + + for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i) + { + rgb[i] = XFASTINT (XCAR (how)) & 0xffff; + how = XCDR (how); + } + + if (i == 3 && NILP (how)) + { + char color_name[30]; + sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]); + bg = ( +#ifdef HAVE_NTGUI + 0x00ffffff & /* Filter out palette info. */ +#endif /* HAVE_NTGUI */ + x_alloc_image_color (f, img, build_string (color_name), 0)); + use_img_background = 0; + } + } + + if (use_img_background) + bg = four_corners_best (ximg, img->width, img->height); + + /* Set all bits in mask_img to 1 whose color in ximg is different + from the background color bg. */ +#ifndef HAVE_NTGUI + for (y = 0; y < img->height; ++y) + for (x = 0; x < img->width; ++x) + XPutPixel (mask_img, x, y, (XGetPixel (ximg, x, y) != bg + ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f))); + + /* Fill in the background_transparent field while we have the mask handy. */ + image_background_transparent (img, f, mask_img); + + /* Put mask_img into img->mask. */ + x_put_x_image (f, mask_img, img->mask, img->width, img->height); + x_destroy_x_image (mask_img); + +#else + for (y = 0; y < img->height; ++y) + for (x = 0; x < img->width; ++x) + { + COLORREF p = GetPixel (ximg, x, y); + if (p != bg) + mask_img[y * row_width + x / 8] |= 1 << (x % 8); + } + + /* Create the mask image. */ + img->mask = w32_create_pixmap_from_bitmap_data (img->width, img->height, + mask_img); + /* Fill in the background_transparent field while we have the mask handy. */ + SelectObject (ximg, img->mask); + image_background_transparent (img, f, ximg); + + /* Was: x_destroy_x_image ((XImagePtr )mask_img); which seems bogus ++kfs */ + xfree (mask_img); +#endif /* HAVE_NTGUI */ + + Destroy_Image (ximg, prev); + + return 1; +} + + +/*********************************************************************** + PBM (mono, gray, color) + ***********************************************************************/ + +static int pbm_image_p P_ ((Lisp_Object object)); +static int pbm_load P_ ((struct frame *f, struct image *img)); +static int pbm_scan_number P_ ((unsigned char **, unsigned char *)); + +/* The symbol `pbm' identifying images of this type. */ + +Lisp_Object Qpbm; + +/* Indices of image specification fields in gs_format, below. */ + +enum pbm_keyword_index +{ + PBM_TYPE, + PBM_FILE, + PBM_DATA, + PBM_ASCENT, + PBM_MARGIN, + PBM_RELIEF, + PBM_ALGORITHM, + PBM_HEURISTIC_MASK, + PBM_MASK, + PBM_FOREGROUND, + PBM_BACKGROUND, + PBM_LAST +}; + +/* Vector of image_keyword structures describing the format + of valid user-defined image specifications. */ + +static struct image_keyword pbm_format[PBM_LAST] = +{ + {":type", IMAGE_SYMBOL_VALUE, 1}, + {":file", IMAGE_STRING_VALUE, 0}, + {":data", IMAGE_STRING_VALUE, 0}, + {":ascent", IMAGE_ASCENT_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, + {":relief", IMAGE_INTEGER_VALUE, 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_OR_NIL_VALUE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} +}; + +/* Structure describing the image type `pbm'. */ + +static struct image_type pbm_type = +{ + &Qpbm, + pbm_image_p, + pbm_load, + x_clear_image, + NULL +}; + + +/* Return non-zero if OBJECT is a valid PBM image specification. */ + +static int +pbm_image_p (object) + Lisp_Object object; +{ + struct image_keyword fmt[PBM_LAST]; + + bcopy (pbm_format, fmt, sizeof fmt); + + if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)) + return 0; + + /* Must specify either :data or :file. */ + return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1; +} + + +/* Scan a decimal number from *S and return it. Advance *S while + reading the number. END is the end of the string. Value is -1 at + end of input. */ + +static int +pbm_scan_number (s, end) + unsigned char **s, *end; +{ + int c = 0, val = -1; + + while (*s < end) + { + /* Skip white-space. */ + while (*s < end && (c = *(*s)++, isspace (c))) + ; + + if (c == '#') + { + /* Skip comment to end of line. */ + while (*s < end && (c = *(*s)++, c != '\n')) + ; + } + else if (isdigit (c)) + { + /* Read decimal number. */ + val = c - '0'; + while (*s < end && (c = *(*s)++, isdigit (c))) + val = 10 * val + c - '0'; + break; + } + else + break; + } + + return val; +} + + +#ifdef HAVE_NTGUI +#if 0 /* Unused. ++kfs */ + +/* Read FILE into memory. Value is a pointer to a buffer allocated + with xmalloc holding FILE's contents. Value is null if an error + occurred. *SIZE is set to the size of the file. */ + +static char * +pbm_read_file (file, size) + Lisp_Object file; + int *size; +{ + FILE *fp = NULL; + char *buf = NULL; + struct stat st; + + if (stat (SDATA (file), &st) == 0 + && (fp = fopen (SDATA (file), "rb")) != NULL + && (buf = (char *) xmalloc (st.st_size), + fread (buf, 1, st.st_size, fp) == st.st_size)) + { + *size = st.st_size; + fclose (fp); + } + else + { + if (fp) + fclose (fp); + if (buf) + { + xfree (buf); + buf = NULL; + } + } + + return buf; +} +#endif +#endif /* HAVE_NTGUI */ + +/* Load PBM image IMG for use on frame F. */ + +static int +pbm_load (f, img) + struct frame *f; + struct image *img; +{ + int raw_p, x, y; + int width, height, max_color_idx = 0; + XImagePtr ximg; + Lisp_Object file, specified_file; + enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type; + struct gcpro gcpro1; + unsigned char *contents = NULL; + unsigned char *end, *p; + int size; + + specified_file = image_spec_value (img->spec, QCfile, NULL); + file = Qnil; + GCPRO1 (file); + + if (STRINGP (specified_file)) + { + file = x_find_image_file (specified_file); + if (!STRINGP (file)) + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + UNGCPRO; + return 0; + } + + contents = slurp_file (SDATA (file), &size); + if (contents == NULL) + { + image_error ("Error reading `%s'", file, Qnil); + UNGCPRO; + return 0; + } + + p = contents; + end = contents + size; + } + else + { + Lisp_Object data; + data = image_spec_value (img->spec, QCdata, NULL); + p = SDATA (data); + end = p + SBYTES (data); + } + + /* Check magic number. */ + if (end - p < 2 || *p++ != 'P') + { + image_error ("Not a PBM image: `%s'", img->spec, Qnil); + error: + xfree (contents); + UNGCPRO; + return 0; + } + + switch (*p++) + { + case '1': + raw_p = 0, type = PBM_MONO; + break; + + case '2': + raw_p = 0, type = PBM_GRAY; + break; + + case '3': + raw_p = 0, type = PBM_COLOR; + break; + + case '4': + raw_p = 1, type = PBM_MONO; + break; + + case '5': + raw_p = 1, type = PBM_GRAY; + break; + + case '6': + raw_p = 1, type = PBM_COLOR; + break; + + default: + image_error ("Not a PBM image: `%s'", img->spec, Qnil); + goto error; + } + + /* Read width, height, maximum color-component. Characters + starting with `#' up to the end of a line are ignored. */ + width = pbm_scan_number (&p, end); + height = pbm_scan_number (&p, end); + + if (type != PBM_MONO) + { + max_color_idx = pbm_scan_number (&p, end); + if (raw_p && max_color_idx > 255) + max_color_idx = 255; + } + + if (width < 0 + || height < 0 + || (type != PBM_MONO && max_color_idx < 0)) + goto error; + + if (!x_create_x_image_and_pixmap (f, width, height, 0, + &ximg, &img->pixmap)) + goto error; + + /* Initialize the color hash table. */ + init_color_table (); + + 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 + && STRINGP (fmt[PBM_FOREGROUND].value)) + fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg); + if (fmt[PBM_BACKGROUND].count + && STRINGP (fmt[PBM_BACKGROUND].value)) + { + bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg); + img->background = bg; + img->background_valid = 1; + } + + for (y = 0; y < height; ++y) + for (x = 0; x < width; ++x) + { + if (raw_p) + { + if ((x & 7) == 0) + c = *p++; + g = c & 0x80; + c <<= 1; + } + else + g = pbm_scan_number (&p, end); + + XPutPixel (ximg, x, y, g ? fg : bg); + } + } + else + { + for (y = 0; y < height; ++y) + for (x = 0; x < width; ++x) + { + int r, g, b; + + if (type == PBM_GRAY) + r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end); + else if (raw_p) + { + r = *p++; + g = *p++; + b = *p++; + } + else + { + r = pbm_scan_number (&p, end); + g = pbm_scan_number (&p, end); + b = pbm_scan_number (&p, end); + } + + if (r < 0 || g < 0 || b < 0) + { + x_destroy_x_image (ximg); + image_error ("Invalid pixel value in image `%s'", + img->spec, Qnil); + goto error; + } + + /* RGB values are now in the range 0..max_color_idx. + Scale this to the range 0..0xffff supported by X. */ + r = (double) r * 65535 / max_color_idx; + g = (double) g * 65535 / max_color_idx; + b = (double) b * 65535 / max_color_idx; + XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b)); + } + } + +#ifdef COLOR_TABLE_SUPPORT + /* Store in IMG->colors the colors allocated for the image, and + free the color table. */ + img->colors = colors_in_color_table (&img->ncolors); + free_color_table (); +#endif /* COLOR_TABLE_SUPPORT */ + + img->width = width; + img->height = height; + + /* Maybe fill in the background field while we have ximg handy. */ + + if (NILP (image_spec_value (img->spec, QCbackground, NULL))) + IMAGE_BACKGROUND (img, f, ximg); + + /* Put the image into a pixmap. */ + x_put_x_image (f, ximg, img->pixmap, width, height); + x_destroy_x_image (ximg); + + /* X and W32 versions did it here, MAC version above. ++kfs + img->width = width; + img->height = height; */ + + UNGCPRO; + xfree (contents); + return 1; +} + + +/*********************************************************************** + PNG + ***********************************************************************/ + +#if defined (HAVE_PNG) || defined (MAC_OS) + +/* Function prototypes. */ + +static int png_image_p P_ ((Lisp_Object object)); +static int png_load P_ ((struct frame *f, struct image *img)); + +/* The symbol `png' identifying images of this type. */ + +Lisp_Object Qpng; + +/* Indices of image specification fields in png_format, below. */ + +enum png_keyword_index +{ + PNG_TYPE, + PNG_DATA, + PNG_FILE, + PNG_ASCENT, + PNG_MARGIN, + PNG_RELIEF, + PNG_ALGORITHM, + PNG_HEURISTIC_MASK, + PNG_MASK, + PNG_BACKGROUND, + PNG_LAST +}; + +/* Vector of image_keyword structures describing the format + of valid user-defined image specifications. */ + +static struct image_keyword png_format[PNG_LAST] = +{ + {":type", IMAGE_SYMBOL_VALUE, 1}, + {":data", IMAGE_STRING_VALUE, 0}, + {":file", IMAGE_STRING_VALUE, 0}, + {":ascent", IMAGE_ASCENT_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, + {":relief", IMAGE_INTEGER_VALUE, 0}, + {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} +}; + +/* Structure describing the image type `png'. */ + +static struct image_type png_type = +{ + &Qpng, + png_image_p, + png_load, + x_clear_image, + NULL +}; + +/* Return non-zero if OBJECT is a valid PNG image specification. */ + +static int +png_image_p (object) + Lisp_Object object; +{ + struct image_keyword fmt[PNG_LAST]; + bcopy (png_format, fmt, sizeof fmt); + + if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)) + return 0; + + /* Must specify either the :data or :file keyword. */ + return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1; +} + +#endif /* HAVE_PNG || MAC_OS */ + + +#ifdef HAVE_PNG + +#if defined HAVE_LIBPNG_PNG_H +# include <libpng/png.h> +#else +# include <png.h> +#endif + +#ifdef HAVE_NTGUI +/* PNG library details. */ + +DEF_IMGLIB_FN (png_get_io_ptr); +DEF_IMGLIB_FN (png_check_sig); +DEF_IMGLIB_FN (png_create_read_struct); +DEF_IMGLIB_FN (png_create_info_struct); +DEF_IMGLIB_FN (png_destroy_read_struct); +DEF_IMGLIB_FN (png_set_read_fn); +DEF_IMGLIB_FN (png_init_io); +DEF_IMGLIB_FN (png_set_sig_bytes); +DEF_IMGLIB_FN (png_read_info); +DEF_IMGLIB_FN (png_get_IHDR); +DEF_IMGLIB_FN (png_get_valid); +DEF_IMGLIB_FN (png_set_strip_16); +DEF_IMGLIB_FN (png_set_expand); +DEF_IMGLIB_FN (png_set_gray_to_rgb); +DEF_IMGLIB_FN (png_set_background); +DEF_IMGLIB_FN (png_get_bKGD); +DEF_IMGLIB_FN (png_read_update_info); +DEF_IMGLIB_FN (png_get_channels); +DEF_IMGLIB_FN (png_get_rowbytes); +DEF_IMGLIB_FN (png_read_image); +DEF_IMGLIB_FN (png_read_end); +DEF_IMGLIB_FN (png_error); + +static int +init_png_functions (void) +{ + HMODULE library; + + /* Ensure zlib is loaded. Try debug version first. */ + if (!LoadLibrary ("zlibd.dll") + && !LoadLibrary ("zlib.dll")) + return 0; + + /* Try loading libpng under probable names. */ + if (!(library = LoadLibrary ("libpng13d.dll")) + && !(library = LoadLibrary ("libpng13.dll")) + && !(library = LoadLibrary ("libpng12d.dll")) + && !(library = LoadLibrary ("libpng12.dll")) + && !(library = LoadLibrary ("libpng.dll"))) + return 0; + + LOAD_IMGLIB_FN (library, png_get_io_ptr); + LOAD_IMGLIB_FN (library, png_check_sig); + LOAD_IMGLIB_FN (library, png_create_read_struct); + LOAD_IMGLIB_FN (library, png_create_info_struct); + LOAD_IMGLIB_FN (library, png_destroy_read_struct); + LOAD_IMGLIB_FN (library, png_set_read_fn); + LOAD_IMGLIB_FN (library, png_init_io); + LOAD_IMGLIB_FN (library, png_set_sig_bytes); + LOAD_IMGLIB_FN (library, png_read_info); + LOAD_IMGLIB_FN (library, png_get_IHDR); + LOAD_IMGLIB_FN (library, png_get_valid); + LOAD_IMGLIB_FN (library, png_set_strip_16); + LOAD_IMGLIB_FN (library, png_set_expand); + LOAD_IMGLIB_FN (library, png_set_gray_to_rgb); + LOAD_IMGLIB_FN (library, png_set_background); + LOAD_IMGLIB_FN (library, png_get_bKGD); + LOAD_IMGLIB_FN (library, png_read_update_info); + LOAD_IMGLIB_FN (library, png_get_channels); + LOAD_IMGLIB_FN (library, png_get_rowbytes); + LOAD_IMGLIB_FN (library, png_read_image); + LOAD_IMGLIB_FN (library, png_read_end); + LOAD_IMGLIB_FN (library, png_error); + return 1; +} +#else + +#define fn_png_get_io_ptr png_get_io_ptr +#define fn_png_check_sig png_check_sig +#define fn_png_create_read_struct png_create_read_struct +#define fn_png_create_info_struct png_create_info_struct +#define fn_png_destroy_read_struct png_destroy_read_struct +#define fn_png_set_read_fn png_set_read_fn +#define fn_png_init_io png_init_io +#define fn_png_set_sig_bytes png_set_sig_bytes +#define fn_png_read_info png_read_info +#define fn_png_get_IHDR png_get_IHDR +#define fn_png_get_valid png_get_valid +#define fn_png_set_strip_16 png_set_strip_16 +#define fn_png_set_expand png_set_expand +#define fn_png_set_gray_to_rgb png_set_gray_to_rgb +#define fn_png_set_background png_set_background +#define fn_png_get_bKGD png_get_bKGD +#define fn_png_read_update_info png_read_update_info +#define fn_png_get_channels png_get_channels +#define fn_png_get_rowbytes png_get_rowbytes +#define fn_png_read_image png_read_image +#define fn_png_read_end png_read_end +#define fn_png_error png_error + +#endif /* HAVE_NTGUI */ + +/* Error and warning handlers installed when the PNG library + is initialized. */ + +static void +my_png_error (png_ptr, msg) + png_struct *png_ptr; + char *msg; +{ + xassert (png_ptr != NULL); + image_error ("PNG error: %s", build_string (msg), Qnil); + longjmp (png_ptr->jmpbuf, 1); +} + + +static void +my_png_warning (png_ptr, msg) + png_struct *png_ptr; + char *msg; +{ + xassert (png_ptr != NULL); + image_error ("PNG warning: %s", build_string (msg), Qnil); +} + +/* Memory source for PNG decoding. */ + +struct png_memory_storage +{ + unsigned char *bytes; /* The data */ + size_t len; /* How big is it? */ + int index; /* Where are we? */ +}; + + +/* Function set as reader function when reading PNG image from memory. + PNG_PTR is a pointer to the PNG control structure. Copy LENGTH + bytes from the input to DATA. */ + +static void +png_read_from_memory (png_ptr, data, length) + png_structp png_ptr; + png_bytep data; + png_size_t length; +{ + struct png_memory_storage *tbr + = (struct png_memory_storage *) fn_png_get_io_ptr (png_ptr); + + if (length > tbr->len - tbr->index) + fn_png_error (png_ptr, "Read error"); + + bcopy (tbr->bytes + tbr->index, data, length); + tbr->index = tbr->index + length; +} + +/* Load PNG image IMG for use on frame F. Value is non-zero if + successful. */ + +static int +png_load (f, img) + struct frame *f; + struct image *img; +{ + Lisp_Object file, specified_file; + Lisp_Object specified_data; + int x, y, i; + XImagePtr ximg, mask_img = NULL; + struct gcpro gcpro1; + png_struct *png_ptr = NULL; + png_info *info_ptr = NULL, *end_info = NULL; + FILE *volatile fp = NULL; + png_byte sig[8]; + png_byte * volatile pixels = NULL; + png_byte ** volatile rows = NULL; + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; + png_byte channels; + png_uint_32 row_bytes; + int transparent_p; + double screen_gamma; + struct png_memory_storage tbr; /* Data to be read */ + + /* Find out what file to load. */ + specified_file = image_spec_value (img->spec, QCfile, NULL); + specified_data = image_spec_value (img->spec, QCdata, NULL); + file = Qnil; + GCPRO1 (file); + + if (NILP (specified_data)) + { + file = x_find_image_file (specified_file); + if (!STRINGP (file)) + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + UNGCPRO; + return 0; + } + + /* Open the image file. */ + fp = fopen (SDATA (file), "rb"); + if (!fp) + { + image_error ("Cannot open image file `%s'", file, Qnil); + UNGCPRO; + fclose (fp); + return 0; + } + + /* Check PNG signature. */ + if (fread (sig, 1, sizeof sig, fp) != sizeof sig + || !fn_png_check_sig (sig, sizeof sig)) + { + image_error ("Not a PNG file: `%s'", file, Qnil); + UNGCPRO; + fclose (fp); + return 0; + } + } + else + { + /* Read from memory. */ + tbr.bytes = SDATA (specified_data); + tbr.len = SBYTES (specified_data); + tbr.index = 0; + + /* Check PNG signature. */ + if (tbr.len < sizeof sig + || !fn_png_check_sig (tbr.bytes, sizeof sig)) + { + image_error ("Not a PNG image: `%s'", img->spec, Qnil); + UNGCPRO; + return 0; + } + + /* Need to skip past the signature. */ + tbr.bytes += sizeof (sig); + } + + /* Initialize read and info structs for PNG lib. */ + png_ptr = fn_png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, + my_png_error, my_png_warning); + if (!png_ptr) + { + if (fp) fclose (fp); + UNGCPRO; + return 0; + } + + info_ptr = fn_png_create_info_struct (png_ptr); + if (!info_ptr) + { + fn_png_destroy_read_struct (&png_ptr, NULL, NULL); + if (fp) fclose (fp); + UNGCPRO; + return 0; + } + + end_info = fn_png_create_info_struct (png_ptr); + if (!end_info) + { + fn_png_destroy_read_struct (&png_ptr, &info_ptr, NULL); + if (fp) fclose (fp); + UNGCPRO; + return 0; + } + + /* Set error jump-back. We come back here when the PNG library + detects an error. */ + if (setjmp (png_ptr->jmpbuf)) + { + error: + if (png_ptr) + fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); + xfree (pixels); + xfree (rows); + if (fp) fclose (fp); + UNGCPRO; + return 0; + } + + /* Read image info. */ + if (!NILP (specified_data)) + fn_png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory); + else + fn_png_init_io (png_ptr, fp); + + fn_png_set_sig_bytes (png_ptr, sizeof sig); + fn_png_read_info (png_ptr, info_ptr); + fn_png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, + &interlace_type, NULL, NULL); + + /* If image contains simply transparency data, we prefer to + construct a clipping mask. */ + if (fn_png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) + transparent_p = 1; + else + transparent_p = 0; + + /* This function is easier to write if we only have to handle + one data format: RGB or RGBA with 8 bits per channel. Let's + transform other formats into that format. */ + + /* Strip more than 8 bits per channel. */ + if (bit_depth == 16) + fn_png_set_strip_16 (png_ptr); + + /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel + if available. */ + fn_png_set_expand (png_ptr); + + /* Convert grayscale images to RGB. */ + if (color_type == PNG_COLOR_TYPE_GRAY + || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + fn_png_set_gray_to_rgb (png_ptr); + + screen_gamma = (f->gamma ? 1 / f->gamma / 0.45455 : 2.2); + +#if 0 /* Avoid double gamma correction for PNG images. */ + { /* Tell the PNG lib to handle gamma correction for us. */ + int intent; + double image_gamma; +#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED) + if (png_get_sRGB (png_ptr, info_ptr, &intent)) + /* The libpng documentation says this is right in this case. */ + png_set_gamma (png_ptr, screen_gamma, 0.45455); + else +#endif + if (png_get_gAMA (png_ptr, info_ptr, &image_gamma)) + /* Image contains gamma information. */ + png_set_gamma (png_ptr, screen_gamma, image_gamma); + else + /* Use the standard default for the image gamma. */ + png_set_gamma (png_ptr, screen_gamma, 0.45455); + } +#endif /* if 0 */ + + /* Handle alpha channel by combining the image with a background + color. Do this only if a real alpha channel is supplied. For + simple transparency, we prefer a clipping mask. */ + if (!transparent_p) + { + png_color_16 *image_bg; + Lisp_Object specified_bg + = image_spec_value (img->spec, QCbackground, NULL); + + if (STRINGP (specified_bg)) + /* The user specified `:background', use that. */ + { + /* W32 version incorrectly used COLORREF here!! ++kfs */ + XColor color; + if (x_defined_color (f, SDATA (specified_bg), &color, 0)) + { + png_color_16 user_bg; + + bzero (&user_bg, sizeof user_bg); + user_bg.red = color.red >> PNG_BG_COLOR_SHIFT; + user_bg.green = color.green >> PNG_BG_COLOR_SHIFT; + user_bg.blue = color.blue >> PNG_BG_COLOR_SHIFT; + + fn_png_set_background (png_ptr, &user_bg, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + } + } + else if (fn_png_get_bKGD (png_ptr, info_ptr, &image_bg)) + /* Image contains a background color with which to + combine the image. */ + fn_png_set_background (png_ptr, image_bg, + PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); + else + { + /* Image does not contain a background color with which + to combine the image data via an alpha channel. Use + the frame's background instead. */ +#ifdef HAVE_X_WINDOWS + XColor color; + png_color_16 frame_background; + + color.pixel = FRAME_BACKGROUND_PIXEL (f); + x_query_color (f, &color); + + bzero (&frame_background, sizeof frame_background); + frame_background.red = color.red; + frame_background.green = color.green; + frame_background.blue = color.blue; +#endif /* HAVE_X_WINDOWS */ + +#ifdef HAVE_NTGUI + COLORREF color; + png_color_16 frame_background; + color = FRAME_BACKGROUND_PIXEL (f); +#if 0 /* W32 TODO : Colormap support. */ + x_query_color (f, &color); +#endif + bzero (&frame_background, sizeof frame_background); + frame_background.red = 256 * GetRValue (color); + frame_background.green = 256 * GetGValue (color); + frame_background.blue = 256 * GetBValue (color); +#endif /* HAVE_NTGUI */ + +#ifdef MAC_OS + unsigned long color; + png_color_16 frame_background; + color = FRAME_BACKGROUND_PIXEL (f); +#if 0 /* MAC/W32 TODO : Colormap support. */ + x_query_color (f, &color); +#endif + bzero (&frame_background, sizeof frame_background); + frame_background.red = RED_FROM_ULONG (color); + frame_background.green = GREEN_FROM_ULONG (color); + frame_background.blue = BLUE_FROM_ULONG (color); +#endif /* MAC_OS */ + + fn_png_set_background (png_ptr, &frame_background, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + } + } + + /* Update info structure. */ + fn_png_read_update_info (png_ptr, info_ptr); + + /* Get number of channels. Valid values are 1 for grayscale images + and images with a palette, 2 for grayscale images with transparency + information (alpha channel), 3 for RGB images, and 4 for RGB + images with alpha channel, i.e. RGBA. If conversions above were + sufficient we should only have 3 or 4 channels here. */ + channels = fn_png_get_channels (png_ptr, info_ptr); + xassert (channels == 3 || channels == 4); + + /* Number of bytes needed for one row of the image. */ + row_bytes = fn_png_get_rowbytes (png_ptr, info_ptr); + + /* Allocate memory for the image. */ + pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels); + rows = (png_byte **) xmalloc (height * sizeof *rows); + for (i = 0; i < height; ++i) + rows[i] = pixels + i * row_bytes; + + /* Read the entire image. */ + fn_png_read_image (png_ptr, rows); + fn_png_read_end (png_ptr, info_ptr); + if (fp) + { + fclose (fp); + fp = NULL; + } + + /* Create the X image and pixmap. */ + if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, + &img->pixmap)) + goto error; + + /* Create an image and pixmap serving as mask if the PNG image + contains an alpha channel. */ + if (channels == 4 + && !transparent_p + && !x_create_x_image_and_pixmap (f, width, height, 1, + &mask_img, &img->mask)) + { + x_destroy_x_image (ximg); + Free_Pixmap (FRAME_X_DISPLAY (f), img->pixmap); + img->pixmap = NO_PIXMAP; + goto error; + } + + /* Fill the X image and mask from PNG data. */ + init_color_table (); + + for (y = 0; y < height; ++y) + { + png_byte *p = rows[y]; + + for (x = 0; x < width; ++x) + { + unsigned r, g, b; + + r = *p++ << 8; + g = *p++ << 8; + b = *p++ << 8; + XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b)); + /* An alpha channel, aka mask channel, associates variable + transparency with an image. Where other image formats + support binary transparency---fully transparent or fully + opaque---PNG allows up to 254 levels of partial transparency. + The PNG library implements partial transparency by combining + the image with a specified background color. + + I'm not sure how to handle this here nicely: because the + background on which the image is displayed may change, for + real alpha channel support, it would be necessary to create + a new image for each possible background. + + What I'm doing now is that a mask is created if we have + boolean transparency information. Otherwise I'm using + the frame's background color to combine the image with. */ + + if (channels == 4) + { + if (mask_img) + XPutPixel (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f)); + ++p; + } + } + } + + if (NILP (image_spec_value (img->spec, QCbackground, NULL))) + /* Set IMG's background color from the PNG image, unless the user + overrode it. */ + { + png_color_16 *bg; + if (fn_png_get_bKGD (png_ptr, info_ptr, &bg)) + { + img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue); + img->background_valid = 1; + } + } + +#ifdef COLOR_TABLE_SUPPORT + /* Remember colors allocated for this image. */ + img->colors = colors_in_color_table (&img->ncolors); + free_color_table (); +#endif /* COLOR_TABLE_SUPPORT */ + + /* Clean up. */ + fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); + xfree (rows); + xfree (pixels); + + img->width = width; + img->height = height; + + /* Maybe fill in the background field while we have ximg handy. */ + IMAGE_BACKGROUND (img, f, ximg); + + /* Put the image into the pixmap, then free the X image and its buffer. */ + x_put_x_image (f, ximg, img->pixmap, width, height); + x_destroy_x_image (ximg); + + /* Same for the mask. */ + if (mask_img) + { + /* Fill in the background_transparent field while we have the mask + handy. */ + image_background_transparent (img, f, mask_img); + + x_put_x_image (f, mask_img, img->mask, img->width, img->height); + x_destroy_x_image (mask_img); + } + + UNGCPRO; + return 1; +} + +#else /* HAVE_PNG */ + +#ifdef MAC_OS +static int +png_load (f, img) + struct frame *f; + struct image *img; +{ +#ifdef MAC_OSX + if (MyCGImageCreateWithPNGDataProvider) + return image_load_quartz2d (f, img, 1); + else +#endif + return image_load_quicktime (f, img, kQTFileTypePNG); +} +#endif /* MAC_OS */ + +#endif /* !HAVE_PNG */ + + + +/*********************************************************************** + JPEG + ***********************************************************************/ + +#if defined (HAVE_JPEG) || defined (MAC_OS) + +static int jpeg_image_p P_ ((Lisp_Object object)); +static int jpeg_load P_ ((struct frame *f, struct image *img)); + +/* The symbol `jpeg' identifying images of this type. */ + +Lisp_Object Qjpeg; + +/* Indices of image specification fields in gs_format, below. */ + +enum jpeg_keyword_index +{ + JPEG_TYPE, + JPEG_DATA, + JPEG_FILE, + JPEG_ASCENT, + JPEG_MARGIN, + JPEG_RELIEF, + JPEG_ALGORITHM, + JPEG_HEURISTIC_MASK, + JPEG_MASK, + JPEG_BACKGROUND, + JPEG_LAST +}; + +/* Vector of image_keyword structures describing the format + of valid user-defined image specifications. */ + +static struct image_keyword jpeg_format[JPEG_LAST] = +{ + {":type", IMAGE_SYMBOL_VALUE, 1}, + {":data", IMAGE_STRING_VALUE, 0}, + {":file", IMAGE_STRING_VALUE, 0}, + {":ascent", IMAGE_ASCENT_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, + {":relief", IMAGE_INTEGER_VALUE, 0}, + {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} +}; + +/* Structure describing the image type `jpeg'. */ + +static struct image_type jpeg_type = +{ + &Qjpeg, + jpeg_image_p, + jpeg_load, + x_clear_image, + NULL +}; + +/* Return non-zero if OBJECT is a valid JPEG image specification. */ + +static int +jpeg_image_p (object) + Lisp_Object object; +{ + struct image_keyword fmt[JPEG_LAST]; + + bcopy (jpeg_format, fmt, sizeof fmt); + + if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)) + return 0; + + /* Must specify either the :data or :file keyword. */ + return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1; +} + +#endif /* HAVE_JPEG || MAC_OS */ + +#ifdef HAVE_JPEG + +/* Work around a warning about HAVE_STDLIB_H being redefined in + jconfig.h. */ +#ifdef HAVE_STDLIB_H +#define HAVE_STDLIB_H_1 +#undef HAVE_STDLIB_H +#endif /* HAVE_STLIB_H */ + +#include <jpeglib.h> +#include <jerror.h> +#include <setjmp.h> + +#ifdef HAVE_STLIB_H_1 +#define HAVE_STDLIB_H 1 +#endif + +#ifdef HAVE_NTGUI + +/* JPEG library details. */ +DEF_IMGLIB_FN (jpeg_CreateDecompress); +DEF_IMGLIB_FN (jpeg_start_decompress); +DEF_IMGLIB_FN (jpeg_finish_decompress); +DEF_IMGLIB_FN (jpeg_destroy_decompress); +DEF_IMGLIB_FN (jpeg_read_header); +DEF_IMGLIB_FN (jpeg_read_scanlines); +DEF_IMGLIB_FN (jpeg_stdio_src); +DEF_IMGLIB_FN (jpeg_std_error); +DEF_IMGLIB_FN (jpeg_resync_to_restart); + +static int +init_jpeg_functions (void) +{ + HMODULE library; + + if (!(library = LoadLibrary ("libjpeg.dll")) + && !(library = LoadLibrary ("jpeg-62.dll")) + && !(library = LoadLibrary ("jpeg.dll"))) + return 0; + + LOAD_IMGLIB_FN (library, jpeg_finish_decompress); + LOAD_IMGLIB_FN (library, jpeg_read_scanlines); + LOAD_IMGLIB_FN (library, jpeg_start_decompress); + LOAD_IMGLIB_FN (library, jpeg_read_header); + LOAD_IMGLIB_FN (library, jpeg_stdio_src); + LOAD_IMGLIB_FN (library, jpeg_CreateDecompress); + LOAD_IMGLIB_FN (library, jpeg_destroy_decompress); + LOAD_IMGLIB_FN (library, jpeg_std_error); + LOAD_IMGLIB_FN (library, jpeg_resync_to_restart); + return 1; +} + +/* Wrapper since we can't directly assign the function pointer + to another function pointer that was declared more completely easily. */ +static boolean +jpeg_resync_to_restart_wrapper(cinfo, desired) + j_decompress_ptr cinfo; + int desired; +{ + return fn_jpeg_resync_to_restart (cinfo, desired); +} + +#else + +#define fn_jpeg_CreateDecompress(a,b,c) jpeg_create_decompress(a) +#define fn_jpeg_start_decompress jpeg_start_decompress +#define fn_jpeg_finish_decompress jpeg_finish_decompress +#define fn_jpeg_destroy_decompress jpeg_destroy_decompress +#define fn_jpeg_read_header jpeg_read_header +#define fn_jpeg_read_scanlines jpeg_read_scanlines +#define fn_jpeg_stdio_src jpeg_stdio_src +#define fn_jpeg_std_error jpeg_std_error +#define jpeg_resync_to_restart_wrapper jpeg_resync_to_restart + +#endif /* HAVE_NTGUI */ + +struct my_jpeg_error_mgr +{ + struct jpeg_error_mgr pub; + jmp_buf setjmp_buffer; +}; + + +static void +my_error_exit (cinfo) + j_common_ptr cinfo; +{ + struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err; + longjmp (mgr->setjmp_buffer, 1); +} + + +/* Init source method for JPEG data source manager. Called by + jpeg_read_header() before any data is actually read. See + libjpeg.doc from the JPEG lib distribution. */ + +static void +our_init_source (cinfo) + j_decompress_ptr cinfo; +{ +} + + +/* Fill input buffer method for JPEG data source manager. Called + whenever more data is needed. We read the whole image in one step, + so this only adds a fake end of input marker at the end. */ + +static boolean +our_fill_input_buffer (cinfo) + j_decompress_ptr cinfo; +{ + /* Insert a fake EOI marker. */ + struct jpeg_source_mgr *src = cinfo->src; + static JOCTET buffer[2]; + + buffer[0] = (JOCTET) 0xFF; + buffer[1] = (JOCTET) JPEG_EOI; + + src->next_input_byte = buffer; + src->bytes_in_buffer = 2; + return TRUE; +} + + +/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src + is the JPEG data source manager. */ + +static void +our_skip_input_data (cinfo, num_bytes) + j_decompress_ptr cinfo; + long num_bytes; +{ + struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src; + + if (src) + { + if (num_bytes > src->bytes_in_buffer) + ERREXIT (cinfo, JERR_INPUT_EOF); + + src->bytes_in_buffer -= num_bytes; + src->next_input_byte += num_bytes; + } +} + + +/* Method to terminate data source. Called by + jpeg_finish_decompress() after all data has been processed. */ + +static void +our_term_source (cinfo) + j_decompress_ptr cinfo; +{ +} + + +/* Set up the JPEG lib for reading an image from DATA which contains + LEN bytes. CINFO is the decompression info structure created for + reading the image. */ + +static void +jpeg_memory_src (cinfo, data, len) + j_decompress_ptr cinfo; + JOCTET *data; + unsigned int len; +{ + struct jpeg_source_mgr *src; + + if (cinfo->src == NULL) + { + /* First time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof (struct jpeg_source_mgr)); + src = (struct jpeg_source_mgr *) cinfo->src; + src->next_input_byte = data; + } + + src = (struct jpeg_source_mgr *) cinfo->src; + src->init_source = our_init_source; + src->fill_input_buffer = our_fill_input_buffer; + src->skip_input_data = our_skip_input_data; + src->resync_to_restart = jpeg_resync_to_restart_wrapper; /* Use default method. */ + src->term_source = our_term_source; + src->bytes_in_buffer = len; + src->next_input_byte = data; +} + + +/* Load image IMG for use on frame F. Patterned after example.c + from the JPEG lib. */ + +static int +jpeg_load (f, img) + struct frame *f; + struct image *img; +{ + struct jpeg_decompress_struct cinfo; + struct my_jpeg_error_mgr mgr; + Lisp_Object file, specified_file; + Lisp_Object specified_data; + FILE * volatile fp = NULL; + JSAMPARRAY buffer; + int row_stride, x, y; + XImagePtr ximg = NULL; + int rc; + unsigned long *colors; + int width, height; + struct gcpro gcpro1; + + /* Open the JPEG file. */ + specified_file = image_spec_value (img->spec, QCfile, NULL); + specified_data = image_spec_value (img->spec, QCdata, NULL); + file = Qnil; + GCPRO1 (file); + + if (NILP (specified_data)) + { + file = x_find_image_file (specified_file); + if (!STRINGP (file)) + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + UNGCPRO; + return 0; + } + + fp = fopen (SDATA (file), "rb"); + if (fp == NULL) + { + image_error ("Cannot open `%s'", file, Qnil); + UNGCPRO; + return 0; + } + } + + /* Customize libjpeg's error handling to call my_error_exit when an + error is detected. This function will perform a longjmp. */ + cinfo.err = fn_jpeg_std_error (&mgr.pub); + mgr.pub.error_exit = my_error_exit; + + if ((rc = setjmp (mgr.setjmp_buffer)) != 0) + { + if (rc == 1) + { + /* Called from my_error_exit. Display a JPEG error. */ + char buffer[JMSG_LENGTH_MAX]; + cinfo.err->format_message ((j_common_ptr) &cinfo, buffer); + image_error ("Error reading JPEG image `%s': %s", img->spec, + build_string (buffer)); + } + + /* Close the input file and destroy the JPEG object. */ + if (fp) + fclose ((FILE *) fp); + fn_jpeg_destroy_decompress (&cinfo); + + /* If we already have an XImage, free that. */ + x_destroy_x_image (ximg); + + /* Free pixmap and colors. */ + x_clear_image (f, img); + + UNGCPRO; + return 0; + } + + /* Create the JPEG decompression object. Let it read from fp. + Read the JPEG image header. */ + fn_jpeg_CreateDecompress (&cinfo, JPEG_LIB_VERSION, sizeof (cinfo)); + + if (NILP (specified_data)) + fn_jpeg_stdio_src (&cinfo, (FILE *) fp); + else + jpeg_memory_src (&cinfo, SDATA (specified_data), + SBYTES (specified_data)); + + fn_jpeg_read_header (&cinfo, TRUE); + + /* Customize decompression so that color quantization will be used. + Start decompression. */ + cinfo.quantize_colors = TRUE; + fn_jpeg_start_decompress (&cinfo); + width = img->width = cinfo.output_width; + height = img->height = cinfo.output_height; + + /* Create X image and pixmap. */ + if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) + longjmp (mgr.setjmp_buffer, 2); + + /* Allocate colors. When color quantization is used, + cinfo.actual_number_of_colors has been set with the number of + colors generated, and cinfo.colormap is a two-dimensional array + of color indices in the range 0..cinfo.actual_number_of_colors. + No more than 255 colors will be generated. */ + { + int i, ir, ig, ib; + + if (cinfo.out_color_components > 2) + ir = 0, ig = 1, ib = 2; + else if (cinfo.out_color_components > 1) + ir = 0, ig = 1, ib = 0; + else + ir = 0, ig = 0, ib = 0; + + /* Use the color table mechanism because it handles colors that + cannot be allocated nicely. Such colors will be replaced with + a default color, and we don't have to care about which colors + can be freed safely, and which can't. */ + init_color_table (); + colors = (unsigned long *) alloca (cinfo.actual_number_of_colors + * sizeof *colors); + + for (i = 0; i < cinfo.actual_number_of_colors; ++i) + { + /* Multiply RGB values with 255 because X expects RGB values + in the range 0..0xffff. */ + int r = cinfo.colormap[ir][i] << 8; + int g = cinfo.colormap[ig][i] << 8; + int b = cinfo.colormap[ib][i] << 8; + colors[i] = lookup_rgb_color (f, r, g, b); + } + +#ifdef COLOR_TABLE_SUPPORT + /* Remember those colors actually allocated. */ + img->colors = colors_in_color_table (&img->ncolors); + free_color_table (); +#endif /* COLOR_TABLE_SUPPORT */ + } + + /* Read pixels. */ + row_stride = width * cinfo.output_components; + buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE, + row_stride, 1); + for (y = 0; y < height; ++y) + { + fn_jpeg_read_scanlines (&cinfo, buffer, 1); + for (x = 0; x < cinfo.output_width; ++x) + XPutPixel (ximg, x, y, colors[buffer[0][x]]); + } + + /* Clean up. */ + fn_jpeg_finish_decompress (&cinfo); + fn_jpeg_destroy_decompress (&cinfo); + if (fp) + fclose ((FILE *) fp); + + /* Maybe fill in the background field while we have ximg handy. */ + if (NILP (image_spec_value (img->spec, QCbackground, NULL))) + IMAGE_BACKGROUND (img, f, ximg); + + /* Put the image into the pixmap. */ + x_put_x_image (f, ximg, img->pixmap, width, height); + x_destroy_x_image (ximg); + UNGCPRO; + return 1; +} + +#else /* HAVE_JPEG */ + +#ifdef MAC_OS +static int +jpeg_load (f, img) + struct frame *f; + struct image *img; +{ +#ifdef MAC_OSX + return image_load_quartz2d (f, img, 0); +#else + return image_load_quicktime (f, img, kQTFileTypeJPEG); +#endif +} +#endif /* MAC_OS */ + +#endif /* !HAVE_JPEG */ + + + +/*********************************************************************** + TIFF + ***********************************************************************/ + +#if defined (HAVE_TIFF) || defined (MAC_OS) + +static int tiff_image_p P_ ((Lisp_Object object)); +static int tiff_load P_ ((struct frame *f, struct image *img)); + +/* The symbol `tiff' identifying images of this type. */ + +Lisp_Object Qtiff; + +/* Indices of image specification fields in tiff_format, below. */ + +enum tiff_keyword_index +{ + TIFF_TYPE, + TIFF_DATA, + TIFF_FILE, + TIFF_ASCENT, + TIFF_MARGIN, + TIFF_RELIEF, + TIFF_ALGORITHM, + TIFF_HEURISTIC_MASK, + TIFF_MASK, + TIFF_BACKGROUND, + TIFF_LAST +}; + +/* Vector of image_keyword structures describing the format + of valid user-defined image specifications. */ + +static struct image_keyword tiff_format[TIFF_LAST] = +{ + {":type", IMAGE_SYMBOL_VALUE, 1}, + {":data", IMAGE_STRING_VALUE, 0}, + {":file", IMAGE_STRING_VALUE, 0}, + {":ascent", IMAGE_ASCENT_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, + {":relief", IMAGE_INTEGER_VALUE, 0}, + {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} +}; + +/* Structure describing the image type `tiff'. */ + +static struct image_type tiff_type = +{ + &Qtiff, + tiff_image_p, + tiff_load, + x_clear_image, + NULL +}; + +/* Return non-zero if OBJECT is a valid TIFF image specification. */ + +static int +tiff_image_p (object) + Lisp_Object object; +{ + struct image_keyword fmt[TIFF_LAST]; + bcopy (tiff_format, fmt, sizeof fmt); + + if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)) + return 0; + + /* Must specify either the :data or :file keyword. */ + return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1; +} + +#endif /* HAVE_TIFF || MAC_OS */ + +#ifdef HAVE_TIFF + +#include <tiffio.h> + +#ifdef HAVE_NTGUI + +/* TIFF library details. */ +DEF_IMGLIB_FN (TIFFSetErrorHandler); +DEF_IMGLIB_FN (TIFFSetWarningHandler); +DEF_IMGLIB_FN (TIFFOpen); +DEF_IMGLIB_FN (TIFFClientOpen); +DEF_IMGLIB_FN (TIFFGetField); +DEF_IMGLIB_FN (TIFFReadRGBAImage); +DEF_IMGLIB_FN (TIFFClose); + +static int +init_tiff_functions (void) +{ + HMODULE library; + + if (!(library = LoadLibrary ("libtiff.dll"))) + return 0; + + LOAD_IMGLIB_FN (library, TIFFSetErrorHandler); + LOAD_IMGLIB_FN (library, TIFFSetWarningHandler); + LOAD_IMGLIB_FN (library, TIFFOpen); + LOAD_IMGLIB_FN (library, TIFFClientOpen); + LOAD_IMGLIB_FN (library, TIFFGetField); + LOAD_IMGLIB_FN (library, TIFFReadRGBAImage); + LOAD_IMGLIB_FN (library, TIFFClose); + return 1; +} + +#else + +#define fn_TIFFSetErrorHandler TIFFSetErrorHandler +#define fn_TIFFSetWarningHandler TIFFSetWarningHandler +#define fn_TIFFOpen TIFFOpen +#define fn_TIFFClientOpen TIFFClientOpen +#define fn_TIFFGetField TIFFGetField +#define fn_TIFFReadRGBAImage TIFFReadRGBAImage +#define fn_TIFFClose TIFFClose + +#endif /* HAVE_NTGUI */ + + +/* Reading from a memory buffer for TIFF images Based on the PNG + memory source, but we have to provide a lot of extra functions. + Blah. + + We really only need to implement read and seek, but I am not + convinced that the TIFF library is smart enough not to destroy + itself if we only hand it the function pointers we need to + override. */ + +typedef struct +{ + unsigned char *bytes; + size_t len; + int index; +} +tiff_memory_source; + +static size_t +tiff_read_from_memory (data, buf, size) + thandle_t data; + tdata_t buf; + tsize_t size; +{ + tiff_memory_source *src = (tiff_memory_source *) data; + + if (size > src->len - src->index) + return (size_t) -1; + bcopy (src->bytes + src->index, buf, size); + src->index += size; + return size; +} + +static size_t +tiff_write_from_memory (data, buf, size) + thandle_t data; + tdata_t buf; + tsize_t size; +{ + return (size_t) -1; +} + +static toff_t +tiff_seek_in_memory (data, off, whence) + thandle_t data; + toff_t off; + int whence; +{ + tiff_memory_source *src = (tiff_memory_source *) data; + int idx; + + switch (whence) + { + case SEEK_SET: /* Go from beginning of source. */ + idx = off; + break; + + case SEEK_END: /* Go from end of source. */ + idx = src->len + off; + break; + + case SEEK_CUR: /* Go from current position. */ + idx = src->index + off; + break; + + default: /* Invalid `whence'. */ + return -1; + } + + if (idx > src->len || idx < 0) + return -1; + + src->index = idx; + return src->index; +} + +static int +tiff_close_memory (data) + thandle_t data; +{ + /* NOOP */ + return 0; +} + +static int +tiff_mmap_memory (data, pbase, psize) + thandle_t data; + tdata_t *pbase; + toff_t *psize; +{ + /* It is already _IN_ memory. */ + return 0; +} + +static void +tiff_unmap_memory (data, base, size) + thandle_t data; + tdata_t base; + toff_t size; +{ + /* We don't need to do this. */ +} + +static toff_t +tiff_size_of_memory (data) + thandle_t data; +{ + return ((tiff_memory_source *) data)->len; +} + + +static void +tiff_error_handler (title, format, ap) + const char *title, *format; + va_list ap; +{ + char buf[512]; + int len; + + len = sprintf (buf, "TIFF error: %s ", title); + vsprintf (buf + len, format, ap); + add_to_log (buf, Qnil, Qnil); +} + + +static void +tiff_warning_handler (title, format, ap) + const char *title, *format; + va_list ap; +{ + char buf[512]; + int len; + + len = sprintf (buf, "TIFF warning: %s ", title); + vsprintf (buf + len, format, ap); + add_to_log (buf, Qnil, Qnil); +} + + +/* Load TIFF image IMG for use on frame F. Value is non-zero if + successful. */ + +static int +tiff_load (f, img) + struct frame *f; + struct image *img; +{ + Lisp_Object file, specified_file; + Lisp_Object specified_data; + TIFF *tiff; + int width, height, x, y; + uint32 *buf; + int rc; + XImagePtr ximg; + struct gcpro gcpro1; + tiff_memory_source memsrc; + + specified_file = image_spec_value (img->spec, QCfile, NULL); + specified_data = image_spec_value (img->spec, QCdata, NULL); + file = Qnil; + GCPRO1 (file); + + fn_TIFFSetErrorHandler (tiff_error_handler); + fn_TIFFSetWarningHandler (tiff_warning_handler); + + if (NILP (specified_data)) + { + /* Read from a file */ + file = x_find_image_file (specified_file); + if (!STRINGP (file)) + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + UNGCPRO; + return 0; + } + + /* Try to open the image file. */ + tiff = fn_TIFFOpen (SDATA (file), "r"); + if (tiff == NULL) + { + image_error ("Cannot open `%s'", file, Qnil); + UNGCPRO; + return 0; + } + } + else + { + /* Memory source! */ + memsrc.bytes = SDATA (specified_data); + memsrc.len = SBYTES (specified_data); + memsrc.index = 0; + + tiff = fn_TIFFClientOpen ("memory_source", "r", &memsrc, + (TIFFReadWriteProc) tiff_read_from_memory, + (TIFFReadWriteProc) tiff_write_from_memory, + tiff_seek_in_memory, + tiff_close_memory, + tiff_size_of_memory, + tiff_mmap_memory, + tiff_unmap_memory); + + if (!tiff) + { + image_error ("Cannot open memory source for `%s'", img->spec, Qnil); + UNGCPRO; + return 0; + } + } + + /* Get width and height of the image, and allocate a raster buffer + of width x height 32-bit values. */ + fn_TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width); + fn_TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height); + buf = (uint32 *) xmalloc (width * height * sizeof *buf); + + rc = fn_TIFFReadRGBAImage (tiff, width, height, buf, 0); + fn_TIFFClose (tiff); + if (!rc) + { + image_error ("Error reading TIFF image `%s'", img->spec, Qnil); + xfree (buf); + UNGCPRO; + return 0; + } + + /* Create the X image and pixmap. */ + if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) + { + xfree (buf); + UNGCPRO; + return 0; + } + + /* Initialize the color table. */ + init_color_table (); + + /* Process the pixel raster. Origin is in the lower-left corner. */ + for (y = 0; y < height; ++y) + { + uint32 *row = buf + y * width; + + for (x = 0; x < width; ++x) + { + uint32 abgr = row[x]; + int r = TIFFGetR (abgr) << 8; + int g = TIFFGetG (abgr) << 8; + int b = TIFFGetB (abgr) << 8; + XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b)); + } + } + +#ifdef COLOR_TABLE_SUPPORT + /* Remember the colors allocated for the image. Free the color table. */ + img->colors = colors_in_color_table (&img->ncolors); + free_color_table (); +#endif /* COLOR_TABLE_SUPPORT */ + + img->width = width; + img->height = height; + + /* Maybe fill in the background field while we have ximg handy. */ + if (NILP (image_spec_value (img->spec, QCbackground, NULL))) + IMAGE_BACKGROUND (img, f, ximg); + + /* Put the image into the pixmap, then free the X image and its buffer. */ + x_put_x_image (f, ximg, img->pixmap, width, height); + x_destroy_x_image (ximg); + xfree (buf); + + UNGCPRO; + return 1; +} + +#else /* HAVE_TIFF */ + +#ifdef MAC_OS +static int +tiff_load (f, img) + struct frame *f; + struct image *img; +{ + return image_load_quicktime (f, img, kQTFileTypeTIFF); +} +#endif /* MAC_OS */ + +#endif /* !HAVE_TIFF */ + + + +/*********************************************************************** + GIF + ***********************************************************************/ + +#if defined (HAVE_GIF) || defined (MAC_OS) + +static int gif_image_p P_ ((Lisp_Object object)); +static int gif_load P_ ((struct frame *f, struct image *img)); + +/* The symbol `gif' identifying images of this type. */ + +Lisp_Object Qgif; + +/* Indices of image specification fields in gif_format, below. */ + +enum gif_keyword_index +{ + GIF_TYPE, + GIF_DATA, + GIF_FILE, + GIF_ASCENT, + GIF_MARGIN, + GIF_RELIEF, + GIF_ALGORITHM, + GIF_HEURISTIC_MASK, + GIF_MASK, + GIF_IMAGE, + GIF_BACKGROUND, + GIF_LAST +}; + +/* Vector of image_keyword structures describing the format + of valid user-defined image specifications. */ + +static struct image_keyword gif_format[GIF_LAST] = +{ + {":type", IMAGE_SYMBOL_VALUE, 1}, + {":data", IMAGE_STRING_VALUE, 0}, + {":file", IMAGE_STRING_VALUE, 0}, + {":ascent", IMAGE_ASCENT_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, + {":relief", IMAGE_INTEGER_VALUE, 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}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} +}; + +/* Structure describing the image type `gif'. */ + +static struct image_type gif_type = +{ + &Qgif, + gif_image_p, + gif_load, + x_clear_image, + NULL +}; + +/* Return non-zero if OBJECT is a valid GIF image specification. */ + +static int +gif_image_p (object) + Lisp_Object object; +{ + struct image_keyword fmt[GIF_LAST]; + bcopy (gif_format, fmt, sizeof fmt); + + if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)) + return 0; + + /* Must specify either the :data or :file keyword. */ + return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1; +} + +#endif /* HAVE_GIF || MAC_OS */ + +#ifdef HAVE_GIF + +#if defined (HAVE_NTGUI) || defined (MAC_OS) +/* avoid conflict with QuickdrawText.h */ +#define DrawText gif_DrawText +#include <gif_lib.h> +#undef DrawText + +#else /* HAVE_NTGUI || MAC_OS */ + +#include <gif_lib.h> + +#endif /* HAVE_NTGUI || MAC_OS */ + + +#ifdef HAVE_NTGUI + +/* GIF library details. */ +DEF_IMGLIB_FN (DGifCloseFile); +DEF_IMGLIB_FN (DGifSlurp); +DEF_IMGLIB_FN (DGifOpen); +DEF_IMGLIB_FN (DGifOpenFileName); + +static int +init_gif_functions (void) +{ + HMODULE library; + + if (!(library = LoadLibrary ("libungif.dll"))) + return 0; + + LOAD_IMGLIB_FN (library, DGifCloseFile); + LOAD_IMGLIB_FN (library, DGifSlurp); + LOAD_IMGLIB_FN (library, DGifOpen); + LOAD_IMGLIB_FN (library, DGifOpenFileName); + return 1; +} + +#else + +#define fn_DGifCloseFile DGifCloseFile +#define fn_DGifSlurp DGifSlurp +#define fn_DGifOpen DGifOpen +#define fn_DGifOpenFileName DGifOpenFileName + +#endif /* HAVE_NTGUI */ + +/* Reading a GIF image from memory + Based on the PNG memory stuff to a certain extent. */ + +typedef struct +{ + unsigned char *bytes; + size_t len; + int index; +} +gif_memory_source; + +/* Make the current memory source available to gif_read_from_memory. + It's done this way because not all versions of libungif support + a UserData field in the GifFileType structure. */ +static gif_memory_source *current_gif_memory_src; + +static int +gif_read_from_memory (file, buf, len) + GifFileType *file; + GifByteType *buf; + int len; +{ + gif_memory_source *src = current_gif_memory_src; + + if (len > src->len - src->index) + return -1; + + bcopy (src->bytes + src->index, buf, len); + src->index += len; + return len; +} + + +/* Load GIF image IMG for use on frame F. Value is non-zero if + successful. */ + +static int +gif_load (f, img) + struct frame *f; + struct image *img; +{ + Lisp_Object file, specified_file; + Lisp_Object specified_data; + int rc, width, height, x, y, i; + XImagePtr ximg; + ColorMapObject *gif_color_map; + unsigned long pixel_colors[256]; + GifFileType *gif; + struct gcpro gcpro1; + Lisp_Object image; + int ino, image_left, image_top, image_width, image_height; + gif_memory_source memsrc; + unsigned char *raster; + + specified_file = image_spec_value (img->spec, QCfile, NULL); + specified_data = image_spec_value (img->spec, QCdata, NULL); + file = Qnil; + GCPRO1 (file); + + if (NILP (specified_data)) + { + file = x_find_image_file (specified_file); + if (!STRINGP (file)) + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + UNGCPRO; + return 0; + } + + /* Open the GIF file. */ + gif = fn_DGifOpenFileName (SDATA (file)); + if (gif == NULL) + { + image_error ("Cannot open `%s'", file, Qnil); + UNGCPRO; + return 0; + } + } + else + { + /* Read from memory! */ + current_gif_memory_src = &memsrc; + memsrc.bytes = SDATA (specified_data); + memsrc.len = SBYTES (specified_data); + memsrc.index = 0; + + gif = fn_DGifOpen(&memsrc, gif_read_from_memory); + if (!gif) + { + image_error ("Cannot open memory source `%s'", img->spec, Qnil); + UNGCPRO; + return 0; + } + } + + /* Read entire contents. */ + rc = fn_DGifSlurp (gif); + if (rc == GIF_ERROR) + { + image_error ("Error reading `%s'", img->spec, Qnil); + fn_DGifCloseFile (gif); + UNGCPRO; + return 0; + } + + image = image_spec_value (img->spec, QCindex, NULL); + ino = INTEGERP (image) ? XFASTINT (image) : 0; + if (ino >= gif->ImageCount) + { + image_error ("Invalid image number `%s' in image `%s'", + image, img->spec); + fn_DGifCloseFile (gif); + UNGCPRO; + return 0; + } + + width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width); + height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height); + + /* Create the X image and pixmap. */ + if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) + { + fn_DGifCloseFile (gif); + UNGCPRO; + return 0; + } + + /* Allocate colors. */ + gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap; + if (!gif_color_map) + gif_color_map = gif->SColorMap; + init_color_table (); + bzero (pixel_colors, sizeof pixel_colors); + + for (i = 0; i < gif_color_map->ColorCount; ++i) + { + int r = gif_color_map->Colors[i].Red << 8; + int g = gif_color_map->Colors[i].Green << 8; + int b = gif_color_map->Colors[i].Blue << 8; + pixel_colors[i] = lookup_rgb_color (f, r, g, b); + } + +#ifdef COLOR_TABLE_SUPPORT + img->colors = colors_in_color_table (&img->ncolors); + free_color_table (); +#endif /* COLOR_TABLE_SUPPORT */ + + /* Clear the part of the screen image that are not covered by + the image from the GIF file. Full animated GIF support + requires more than can be done here (see the gif89 spec, + disposal methods). Let's simply assume that the part + not covered by a sub-image is in the frame's background color. */ + image_top = gif->SavedImages[ino].ImageDesc.Top; + image_left = gif->SavedImages[ino].ImageDesc.Left; + image_width = gif->SavedImages[ino].ImageDesc.Width; + image_height = gif->SavedImages[ino].ImageDesc.Height; + + for (y = 0; y < image_top; ++y) + for (x = 0; x < width; ++x) + XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); + + for (y = image_top + image_height; y < height; ++y) + for (x = 0; x < width; ++x) + XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); + + for (y = image_top; y < image_top + image_height; ++y) + { + for (x = 0; x < image_left; ++x) + XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); + for (x = image_left + image_width; x < width; ++x) + XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); + } + + /* Read the GIF image into the X image. We use a local variable + `raster' here because RasterBits below is a char *, and invites + problems with bytes >= 0x80. */ + raster = (unsigned char *) gif->SavedImages[ino].RasterBits; + + if (gif->SavedImages[ino].ImageDesc.Interlace) + { + static int interlace_start[] = {0, 4, 2, 1}; + static int interlace_increment[] = {8, 8, 4, 2}; + int pass; + int row = interlace_start[0]; + + pass = 0; + + for (y = 0; y < image_height; y++) + { + if (row >= image_height) + { + row = interlace_start[++pass]; + while (row >= image_height) + row = interlace_start[++pass]; + } + + for (x = 0; x < image_width; x++) + { + int i = raster[(y * image_width) + x]; + XPutPixel (ximg, x + image_left, row + image_top, + pixel_colors[i]); + } + + row += interlace_increment[pass]; + } + } + else + { + for (y = 0; y < image_height; ++y) + for (x = 0; x < image_width; ++x) + { + int i = raster[y * image_width + x]; + XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]); + } + } + + fn_DGifCloseFile (gif); + + /* Maybe fill in the background field while we have ximg handy. */ + if (NILP (image_spec_value (img->spec, QCbackground, NULL))) + IMAGE_BACKGROUND (img, f, ximg); + + /* Put the image into the pixmap, then free the X image and its buffer. */ + x_put_x_image (f, ximg, img->pixmap, width, height); + x_destroy_x_image (ximg); + + UNGCPRO; + return 1; +} + +#else + +#ifdef MAC_OS +static int +gif_load (f, img) + struct frame *f; + struct image *img; +{ + Lisp_Object specified_file, file; + Lisp_Object specified_data; + OSErr err; + Boolean graphic_p, movie_p, prefer_graphic_p; + Handle dh = NULL; + Movie movie = NULL; + Lisp_Object image; + Track track = NULL; + Media media = NULL; + long nsamples; + Rect rect; + Lisp_Object specified_bg; + XColor color; + RGBColor bg_color; + int width, height; + XImagePtr ximg; + TimeValue time; + struct gcpro gcpro1; + int ino; + + specified_file = image_spec_value (img->spec, QCfile, NULL); + specified_data = image_spec_value (img->spec, QCdata, NULL); + + if (NILP (specified_data)) + { + /* Read from a file */ + FSSpec fss; + short refnum; + + err = find_image_fsspec (specified_file, &file, &fss); + if (err != noErr) + { + if (err == fnfErr) + image_error ("Cannot find image file `%s'", specified_file, Qnil); + else + goto open_error; + } + + err = CanQuickTimeOpenFile (&fss, kQTFileTypeGIF, 0, + &graphic_p, &movie_p, &prefer_graphic_p, 0); + if (err != noErr) + goto open_error; + + if (!graphic_p && !movie_p) + goto open_error; + if (prefer_graphic_p) + return image_load_qt_1 (f, img, kQTFileTypeGIF, &fss, NULL); + err = OpenMovieFile (&fss, &refnum, fsRdPerm); + if (err != noErr) + goto open_error; + err = NewMovieFromFile (&movie, refnum, NULL, NULL, 0, NULL); + CloseMovieFile (refnum); + if (err != noErr) + { + image_error ("Error reading `%s'", file, Qnil); + return 0; + } + } + else + { + /* Memory source! */ + Handle dref = NULL; + long file_type_atom[3]; + + err = PtrToHand (SDATA (specified_data), &dh, SBYTES (specified_data)); + if (err != noErr) + { + image_error ("Cannot allocate data handle for `%s'", + img->spec, Qnil); + goto error; + } + + file_type_atom[0] = EndianU32_NtoB (sizeof (long) * 3); + file_type_atom[1] = EndianU32_NtoB (kDataRefExtensionMacOSFileType); + file_type_atom[2] = EndianU32_NtoB (kQTFileTypeGIF); + err = PtrToHand (&dh, &dref, sizeof (Handle)); + if (err == noErr) + /* no file name */ + err = PtrAndHand ("\p", dref, 1); + if (err == noErr) + err = PtrAndHand (file_type_atom, dref, sizeof (long) * 3); + if (err != noErr) + { + image_error ("Cannot allocate handle data ref for `%s'", img->spec, Qnil); + goto error; + } + err = CanQuickTimeOpenDataRef (dref, HandleDataHandlerSubType, &graphic_p, + &movie_p, &prefer_graphic_p, 0); + if (err != noErr) + goto open_error; + + if (!graphic_p && !movie_p) + goto open_error; + if (prefer_graphic_p) + { + int success_p; + + DisposeHandle (dref); + success_p = image_load_qt_1 (f, img, kQTFileTypeGIF, NULL, dh); + DisposeHandle (dh); + return success_p; + } + err = NewMovieFromDataRef (&movie, 0, NULL, dref, + HandleDataHandlerSubType); + DisposeHandle (dref); + if (err != noErr) + goto open_error; + } + + image = image_spec_value (img->spec, QCindex, NULL); + ino = INTEGERP (image) ? XFASTINT (image) : 0; + track = GetMovieIndTrack (movie, 1); + media = GetTrackMedia (track); + nsamples = GetMediaSampleCount (media); + if (ino >= nsamples) + { + image_error ("Invalid image number `%s' in image `%s'", + image, img->spec); + goto error; + } + + specified_bg = image_spec_value (img->spec, QCbackground, NULL); + if (!STRINGP (specified_bg) || + !mac_defined_color (f, SDATA (specified_bg), &color, 0)) + { + color.pixel = FRAME_BACKGROUND_PIXEL (f); + color.red = RED16_FROM_ULONG (color.pixel); + color.green = GREEN16_FROM_ULONG (color.pixel); + color.blue = BLUE16_FROM_ULONG (color.pixel); + } + GetMovieBox (movie, &rect); + width = img->width = rect.right - rect.left; + height = img->height = rect.bottom - rect.top; + if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) + goto error; + + SetGWorld (ximg, NULL); + bg_color.red = color.red; + bg_color.green = color.green; + bg_color.blue = color.blue; + RGBBackColor (&bg_color); + SetMovieActive (movie, TRUE); + SetMovieGWorld (movie, ximg, NULL); + SampleNumToMediaTime (media, ino + 1, &time, NULL); + SetMovieTimeValue (movie, time); + MoviesTask (movie, 0L); + DisposeTrackMedia (media); + DisposeMovieTrack (track); + DisposeMovie (movie); + if (dh) + DisposeHandle (dh); + /* Maybe fill in the background field while we have ximg handy. */ + if (NILP (image_spec_value (img->spec, QCbackground, NULL))) + IMAGE_BACKGROUND (img, f, ximg); + + /* Put the image into the pixmap. */ + x_put_x_image (f, ximg, img->pixmap, width, height); + x_destroy_x_image (ximg); + return 1; + + open_error: + image_error ("Cannot open `%s'", file, Qnil); + error: + if (media) + DisposeTrackMedia (media); + if (track) + DisposeMovieTrack (track); + if (movie) + DisposeMovie (movie); + if (dh) + DisposeHandle (dh); + return 0; +} +#endif /* MAC_OS */ + +#endif /* HAVE_GIF */ + + + +/*********************************************************************** + Ghostscript + ***********************************************************************/ + +#ifdef HAVE_X_WINDOWS +#define HAVE_GHOSTSCRIPT 1 +#endif /* HAVE_X_WINDOWS */ + +/* The symbol `postscript' identifying images of this type. */ + +Lisp_Object Qpostscript; + +#ifdef HAVE_GHOSTSCRIPT + +static int gs_image_p P_ ((Lisp_Object object)); +static int gs_load P_ ((struct frame *f, struct image *img)); +static void gs_clear_image P_ ((struct frame *f, struct image *img)); + +/* Keyword symbols. */ + +Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height; + +/* Indices of image specification fields in gs_format, below. */ + +enum gs_keyword_index +{ + GS_TYPE, + GS_PT_WIDTH, + GS_PT_HEIGHT, + GS_FILE, + GS_LOADER, + GS_BOUNDING_BOX, + GS_ASCENT, + GS_MARGIN, + GS_RELIEF, + GS_ALGORITHM, + GS_HEURISTIC_MASK, + GS_MASK, + GS_BACKGROUND, + GS_LAST +}; + +/* Vector of image_keyword structures describing the format + of valid user-defined image specifications. */ + +static struct image_keyword gs_format[GS_LAST] = +{ + {":type", IMAGE_SYMBOL_VALUE, 1}, + {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1}, + {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1}, + {":file", IMAGE_STRING_VALUE, 1}, + {":loader", IMAGE_FUNCTION_VALUE, 0}, + {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1}, + {":ascent", IMAGE_ASCENT_VALUE, 0}, + {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, + {":relief", IMAGE_INTEGER_VALUE, 0}, + {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} +}; + +/* Structure describing the image type `ghostscript'. */ + +static struct image_type gs_type = +{ + &Qpostscript, + gs_image_p, + gs_load, + gs_clear_image, + NULL +}; + + +/* Free X resources of Ghostscript image IMG which is used on frame F. */ + +static void +gs_clear_image (f, img) + struct frame *f; + struct image *img; +{ + /* IMG->data.ptr_val may contain a recorded colormap. */ + xfree (img->data.ptr_val); + x_clear_image (f, img); +} + + +/* Return non-zero if OBJECT is a valid Ghostscript image + specification. */ + +static int +gs_image_p (object) + Lisp_Object object; +{ + struct image_keyword fmt[GS_LAST]; + Lisp_Object tem; + int i; + + bcopy (gs_format, fmt, sizeof fmt); + + if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)) + return 0; + + /* Bounding box must be a list or vector containing 4 integers. */ + tem = fmt[GS_BOUNDING_BOX].value; + if (CONSP (tem)) + { + for (i = 0; i < 4; ++i, tem = XCDR (tem)) + if (!CONSP (tem) || !INTEGERP (XCAR (tem))) + return 0; + if (!NILP (tem)) + return 0; + } + else if (VECTORP (tem)) + { + if (XVECTOR (tem)->size != 4) + return 0; + for (i = 0; i < 4; ++i) + if (!INTEGERP (XVECTOR (tem)->contents[i])) + return 0; + } + else + return 0; + + return 1; +} + + +/* Load Ghostscript image IMG for use on frame F. Value is non-zero + if successful. */ + +static int +gs_load (f, img) + struct frame *f; + struct image *img; +{ + char buffer[100]; + Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width; + struct gcpro gcpro1, gcpro2; + Lisp_Object frame; + double in_width, in_height; + Lisp_Object pixel_colors = Qnil; + + /* Compute pixel size of pixmap needed from the given size in the + image specification. Sizes in the specification are in pt. 1 pt + = 1/72 in, xdpi and ydpi are stored in the frame's X display + info. */ + pt_width = image_spec_value (img->spec, QCpt_width, NULL); + in_width = XFASTINT (pt_width) / 72.0; + img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx; + pt_height = image_spec_value (img->spec, QCpt_height, NULL); + in_height = XFASTINT (pt_height) / 72.0; + img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy; + + /* Create the pixmap. */ + xassert (img->pixmap == NO_PIXMAP); + + /* Only W32 version did BLOCK_INPUT here. ++kfs */ + BLOCK_INPUT; + img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + img->width, img->height, + DefaultDepthOfScreen (FRAME_X_SCREEN (f))); + UNBLOCK_INPUT; + + if (!img->pixmap) + { + image_error ("Unable to create pixmap for `%s'", img->spec, Qnil); + return 0; + } + + /* Call the loader to fill the pixmap. It returns a process object + if successful. We do not record_unwind_protect here because + other places in redisplay like calling window scroll functions + don't either. Let the Lisp loader use `unwind-protect' instead. */ + GCPRO2 (window_and_pixmap_id, pixel_colors); + + sprintf (buffer, "%lu %lu", + (unsigned long) FRAME_X_WINDOW (f), + (unsigned long) img->pixmap); + window_and_pixmap_id = build_string (buffer); + + sprintf (buffer, "%lu %lu", + FRAME_FOREGROUND_PIXEL (f), + FRAME_BACKGROUND_PIXEL (f)); + pixel_colors = build_string (buffer); + + XSETFRAME (frame, f); + loader = image_spec_value (img->spec, QCloader, NULL); + if (NILP (loader)) + loader = intern ("gs-load-image"); + + img->data.lisp_val = call6 (loader, frame, img->spec, + make_number (img->width), + make_number (img->height), + window_and_pixmap_id, + pixel_colors); + UNGCPRO; + return PROCESSP (img->data.lisp_val); +} + + +/* Kill the Ghostscript process that was started to fill PIXMAP on + frame F. Called from XTread_socket when receiving an event + telling Emacs that Ghostscript has finished drawing. */ + +void +x_kill_gs_process (pixmap, f) + Pixmap pixmap; + struct frame *f; +{ + struct image_cache *c = FRAME_X_IMAGE_CACHE (f); + int class, i; + struct image *img; + + /* Find the image containing PIXMAP. */ + for (i = 0; i < c->used; ++i) + if (c->images[i]->pixmap == pixmap) + break; + + /* Should someone in between have cleared the image cache, for + instance, give up. */ + if (i == c->used) + return; + + /* Kill the GS process. We should have found PIXMAP in the image + cache and its image should contain a process object. */ + img = c->images[i]; + xassert (PROCESSP (img->data.lisp_val)); + Fkill_process (img->data.lisp_val, Qnil); + img->data.lisp_val = Qnil; + +#if defined (HAVE_X_WINDOWS) + + /* On displays with a mutable colormap, figure out the colors + allocated for the image by looking at the pixels of an XImage for + img->pixmap. */ + class = FRAME_X_VISUAL (f)->class; + if (class != StaticColor && class != StaticGray && class != TrueColor) + { + XImagePtr ximg; + + BLOCK_INPUT; + + /* Try to get an XImage for img->pixmep. */ + ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap, + 0, 0, img->width, img->height, ~0, ZPixmap); + if (ximg) + { + int x, y; + + /* Initialize the color table. */ + init_color_table (); + + /* For each pixel of the image, look its color up in the + color table. After having done so, the color table will + contain an entry for each color used by the image. */ + for (y = 0; y < img->height; ++y) + for (x = 0; x < img->width; ++x) + { + unsigned long pixel = XGetPixel (ximg, x, y); + lookup_pixel_color (f, pixel); + } + + /* Record colors in the image. Free color table and XImage. */ +#ifdef COLOR_TABLE_SUPPORT + img->colors = colors_in_color_table (&img->ncolors); + free_color_table (); +#endif + XDestroyImage (ximg); + +#if 0 /* This doesn't seem to be the case. If we free the colors + here, we get a BadAccess later in x_clear_image when + freeing the colors. */ + /* We have allocated colors once, but Ghostscript has also + allocated colors on behalf of us. So, to get the + reference counts right, free them once. */ + if (img->ncolors) + x_free_colors (f, img->colors, img->ncolors); +#endif + } + else + image_error ("Cannot get X image of `%s'; colors will not be freed", + img->spec, Qnil); + + UNBLOCK_INPUT; + } +#endif /* HAVE_X_WINDOWS */ + + /* Now that we have the pixmap, compute mask and transform the + image if requested. */ + BLOCK_INPUT; + postprocess_image (f, img); + UNBLOCK_INPUT; +} + +#endif /* HAVE_GHOSTSCRIPT */ + + +/*********************************************************************** + Tests + ***********************************************************************/ + +#if GLYPH_DEBUG + +DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0, + doc: /* Value is non-nil if SPEC is a valid image specification. */) + (spec) + Lisp_Object spec; +{ + return valid_image_p (spec) ? Qt : Qnil; +} + + +DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "") + (spec) + Lisp_Object spec; +{ + int id = -1; + + if (valid_image_p (spec)) + id = lookup_image (SELECTED_FRAME (), spec); + + debug_print (spec); + return make_number (id); +} + +#endif /* GLYPH_DEBUG != 0 */ + + +/*********************************************************************** + Initialization + ***********************************************************************/ + +void +syms_of_image () +{ + QCascent = intern (":ascent"); + staticpro (&QCascent); + QCmargin = intern (":margin"); + staticpro (&QCmargin); + QCrelief = intern (":relief"); + staticpro (&QCrelief); + QCconversion = intern (":conversion"); + staticpro (&QCconversion); + QCcolor_symbols = intern (":color-symbols"); + staticpro (&QCcolor_symbols); + QCheuristic_mask = intern (":heuristic-mask"); + staticpro (&QCheuristic_mask); + QCindex = intern (":index"); + staticpro (&QCindex); + QCmatrix = intern (":matrix"); + staticpro (&QCmatrix); + QCcolor_adjustment = intern (":color-adjustment"); + staticpro (&QCcolor_adjustment); + QCmask = intern (":mask"); + staticpro (&QCmask); + + Qlaplace = intern ("laplace"); + staticpro (&Qlaplace); + Qemboss = intern ("emboss"); + staticpro (&Qemboss); + Qedge_detection = intern ("edge-detection"); + staticpro (&Qedge_detection); + Qheuristic = intern ("heuristic"); + staticpro (&Qheuristic); + + Qpostscript = intern ("postscript"); + staticpro (&Qpostscript); +#ifdef HAVE_GHOSTSCRIPT + QCloader = intern (":loader"); + staticpro (&QCloader); + QCbounding_box = intern (":bounding-box"); + staticpro (&QCbounding_box); + QCpt_width = intern (":pt-width"); + staticpro (&QCpt_width); + QCpt_height = intern (":pt-height"); + staticpro (&QCpt_height); +#endif /* HAVE_GHOSTSCRIPT */ + + Qpbm = intern ("pbm"); + staticpro (&Qpbm); + + Qxbm = intern ("xbm"); + staticpro (&Qxbm); + +#ifdef HAVE_XPM + Qxpm = intern ("xpm"); + staticpro (&Qxpm); +#endif + +#if defined (HAVE_JPEG) || defined (MAC_OS) + Qjpeg = intern ("jpeg"); + staticpro (&Qjpeg); +#endif + +#if defined (HAVE_TIFF) || defined (MAC_OS) + Qtiff = intern ("tiff"); + staticpro (&Qtiff); +#endif + +#if defined (HAVE_GIF) || defined (MAC_OS) + Qgif = intern ("gif"); + staticpro (&Qgif); +#endif + +#if defined (HAVE_PNG) || defined (MAC_OS) + Qpng = intern ("png"); + staticpro (&Qpng); +#endif + + defsubr (&Sclear_image_cache); + defsubr (&Simage_size); + defsubr (&Simage_mask_p); + +#if GLYPH_DEBUG + defsubr (&Simagep); + defsubr (&Slookup_image); +#endif + + DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images, + doc: /* Non-nil means always draw a cross over disabled images. +Disabled images are those having an `:conversion disabled' property. +A cross is always drawn on black & white displays. */); + cross_disabled_images = 0; + + DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path, + doc: /* List of directories to search for window system bitmap files. */); + Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS); + + DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay, + doc: /* Time after which cached images are removed from the cache. +When an image has not been displayed this many seconds, remove it +from the image cache. Value must be an integer or nil with nil +meaning don't clear the cache. */); + Vimage_cache_eviction_delay = make_number (30 * 60); +} + + +#ifdef HAVE_NTGUI +/* Image types that rely on external libraries are loaded dynamically + if the library is available. */ +#define IF_LIB_AVAILABLE(init_lib_fn) if (init_lib_fn()) +#else +#define IF_LIB_AVAILABLE(init_func) /* Load unconditionally */ +#endif /* HAVE_NTGUI */ + +void +init_image () +{ + image_types = NULL; + Vimage_types = Qnil; + + define_image_type (&xbm_type); + define_image_type (&pbm_type); + +#ifdef HAVE_XPM + IF_LIB_AVAILABLE(init_xpm_functions) + define_image_type (&xpm_type); +#endif + +#if defined (HAVE_JPEG) || defined (MAC_OS) + IF_LIB_AVAILABLE(init_jpeg_functions) + define_image_type (&jpeg_type); +#endif + +#if defined (HAVE_TIFF) || defined (MAC_OS) + IF_LIB_AVAILABLE(init_tiff_functions) + define_image_type (&tiff_type); +#endif + +#if defined (HAVE_GIF) || defined (MAC_OS) + IF_LIB_AVAILABLE(init_gif_functions) + define_image_type (&gif_type); +#endif + +#if defined (HAVE_PNG) || defined (MAC_OS) + IF_LIB_AVAILABLE(init_png_functions) + define_image_type (&png_type); +#endif + +#ifdef HAVE_GHOSTSCRIPT + define_image_type (&gs_type); +#endif + +#ifdef MAC_OS + /* Animated gifs use QuickTime Movie Toolbox. So initialize it here. */ + EnterMovies (); +#ifdef MAC_OSX + init_image_func_pointer (); +#endif +#endif +} + +/* arch-tag: 123c2a5e-14a8-4c53-ab95-af47d7db49b9 + (do not change this comment) */ diff --git a/src/indent.c b/src/indent.c index ff5eb2f06ba..15e433b03d9 100644 --- a/src/indent.c +++ b/src/indent.c @@ -1197,7 +1197,6 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, = (INTEGERP (current_buffer->selective_display) ? XINT (current_buffer->selective_display) : !NILP (current_buffer->selective_display) ? -1 : 0); - int prev_hpos = 0; int selective_rlen = (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp)) ? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 0); @@ -1225,6 +1224,8 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, int wide_column_end_hpos = 0; int prev_pos; /* Previous buffer position. */ int prev_pos_byte; /* Previous buffer position. */ + int prev_hpos = 0; + int prev_vpos = 0; int contin_hpos; /* HPOS of last column of continued line. */ int prev_tab_offset; /* Previous tab offset. */ @@ -1273,6 +1274,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, pos = prev_pos; pos_byte = prev_pos_byte; hpos = prev_hpos; + vpos = prev_vpos; tab_offset = prev_tab_offset; } break; @@ -1382,6 +1384,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, if (pos >= next_boundary) next_boundary = pos + 1; prev_hpos = width; + prev_vpos = vpos; prev_tab_offset = tab_offset; } } @@ -1414,6 +1417,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, pos = prev_pos; pos_byte = prev_pos_byte; hpos = prev_hpos; + vpos = prev_vpos; tab_offset = prev_tab_offset; /* NOTE on contin_hpos, hpos, and prev_hpos. @@ -1434,10 +1438,6 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, hpos = contin_hpos; vpos = vpos - 1; } - else if (c == '\n') - /* If previous character is NEWLINE, - set VPOS back to previous line */ - vpos = vpos - 1; break; } @@ -1455,6 +1455,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, pos = prev_pos; pos_byte = prev_pos_byte; hpos = prev_hpos; + vpos = prev_vpos; tab_offset = prev_tab_offset; } break; @@ -1463,6 +1464,7 @@ compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, break; prev_hpos = hpos; + prev_vpos = vpos; prev_pos = pos; prev_pos_byte = pos_byte; wide_column_end_hpos = 0; @@ -1834,9 +1836,7 @@ vmotion (from, vtarget, w) register int from, vtarget; struct window *w; { - /* We don't need to make room for continuation marks (we have fringes now), - so hould we really subtract 1 here if FRAME_WINDOW_P ? ++KFS */ - int width = window_box_text_cols (w) - 1; + int width = window_box_text_cols (w); int hscroll = XINT (w->hscroll); struct position pos; /* vpos is cumulative vertical position, changed as from is changed */ @@ -1857,6 +1857,12 @@ vmotion (from, vtarget, w) XSETWINDOW (window, w); + /* We must make room for continuation marks if we don't have fringes. */ +#ifdef HAVE_WINDOW_SYSTEM + if (!FRAME_WINDOW_P (XFRAME (w->frame))) +#endif + width -= 1; + /* If the window contains this buffer, use it for getting text properties. Otherwise use the current buffer as arg for doing that. */ if (EQ (w->buffer, Fcurrent_buffer ())) @@ -2063,3 +2069,6 @@ Setting this variable automatically makes it local to the current buffer. */); defsubr (&Svertical_motion); defsubr (&Scompute_motion); } + +/* arch-tag: 9adfea44-71f7-4988-8ee3-96da15c502cc + (do not change this comment) */ diff --git a/src/indent.h b/src/indent.h index 0ce7238ec75..8c2d1f36adb 100644 --- a/src/indent.h +++ b/src/indent.h @@ -71,3 +71,5 @@ void recompute_width_table P_ ((struct buffer *buf, struct Lisp_Char_Table *disptab)); +/* arch-tag: f9feb373-5bff-4f4f-9198-94805d00cfd7 + (do not change this comment) */ diff --git a/src/insdel.c b/src/insdel.c index 405b3835213..b1ba5a554a8 100644 --- a/src/insdel.c +++ b/src/insdel.c @@ -441,9 +441,13 @@ adjust_markers_for_insert (from, from_byte, to, to_byte, before_markers) } /* Adjusting only markers whose insertion-type is t may result in - disordered overlays in the slot `overlays_before'. */ + - disordered start and end in overlays, and + - disordered overlays in the slot `overlays_before' of current_buffer. */ if (adjusted) - fix_overlays_before (current_buffer, from, to); + { + fix_start_end_in_overlays(from, to); + fix_overlays_before (current_buffer, from, to); + } } /* Adjust point for an insertion of NBYTES bytes, which are NCHARS characters. @@ -2314,3 +2318,6 @@ as well as hooks attached to text properties and overlays. */); defsubr (&Scombine_after_change_execute); } + +/* arch-tag: 9b34b886-47d7-465e-a234-299af411b23d + (do not change this comment) */ diff --git a/src/intervals.c b/src/intervals.c index e19f09609be..d87b361a223 100644 --- a/src/intervals.c +++ b/src/intervals.c @@ -1712,6 +1712,7 @@ graft_intervals_into_buffer (source, position, length, buffer, inherit) { register INTERVAL under, over, this, prev; register INTERVAL tree; + int over_used; tree = BUF_INTERVALS (buffer); @@ -1745,6 +1746,7 @@ graft_intervals_into_buffer (source, position, length, buffer, inherit) XSETBUFFER (buf, buffer); BUF_INTERVALS (buffer) = reproduce_tree_obj (source, buf); BUF_INTERVALS (buffer)->position = BEG; + BUF_INTERVALS (buffer)->up_obj = 1; /* Explicitly free the old tree here? */ @@ -1767,6 +1769,7 @@ graft_intervals_into_buffer (source, position, length, buffer, inherit) { BUF_INTERVALS (buffer) = reproduce_tree (source, INTERVAL_PARENT (tree)); BUF_INTERVALS (buffer)->position = BEG; + BUF_INTERVALS (buffer)->up_obj = 1; /* Explicitly free the old tree here. */ return; @@ -1814,21 +1817,42 @@ graft_intervals_into_buffer (source, position, length, buffer, inherit) adjust_intervals_for_insertion, so stickiness has already been taken care of. */ + /* OVER is the interval we are copying from next. + OVER_USED says how many characters' worth of OVER + have already been copied into target intervals. + UNDER is the next interval in the target. */ + over_used = 0; while (! NULL_INTERVAL_P (over)) { - if (LENGTH (over) < LENGTH (under)) + /* If UNDER is longer than OVER, split it. */ + if (LENGTH (over) - over_used < LENGTH (under)) { - this = split_interval_left (under, LENGTH (over)); + this = split_interval_left (under, LENGTH (over) - over_used); copy_properties (under, this); } else this = under; - copy_properties (over, this); + + /* THIS is now the interval to copy or merge into. + OVER covers all of it. */ if (inherit) merge_properties (over, this); else copy_properties (over, this); - over = next_interval (over); + + /* If THIS and OVER end at the same place, + advance OVER to a new source interval. */ + if (LENGTH (this) == LENGTH (over) - over_used) + { + over = next_interval (over); + over_used = 0; + } + else + /* Otherwise just record that more of OVER has been used. */ + over_used += LENGTH (this); + + /* Always advance to a new target interval. */ + under = next_interval (this); } if (! NULL_INTERVAL_P (BUF_INTERVALS (buffer))) @@ -2587,3 +2611,6 @@ set_intervals_multibyte (multi_flag) set_intervals_multibyte_1 (BUF_INTERVALS (current_buffer), multi_flag, BEG, BEG_BYTE, Z, Z_BYTE); } + +/* arch-tag: 3d402b60-083c-4271-b4a3-ebd9a74bfe27 + (do not change this comment) */ diff --git a/src/intervals.h b/src/intervals.h index 6affe8216b3..a8b011f4d92 100644 --- a/src/intervals.h +++ b/src/intervals.h @@ -328,6 +328,7 @@ extern Lisp_Object Vtext_property_default_nonsticky; extern Lisp_Object Qfront_sticky, Qrear_nonsticky; EXFUN (Fget_char_property, 3); +EXFUN (Fget_char_property_and_overlay, 3); EXFUN (Fget_text_property, 3); EXFUN (Ftext_properties_at, 2); EXFUN (Fnext_property_change, 3); @@ -361,3 +362,6 @@ extern Lisp_Object get_pos_property P_ ((Lisp_Object pos, Lisp_Object prop, extern void syms_of_textprop P_ ((void)); #include "composite.h" + +/* arch-tag: f0bc16c0-b084-498d-9de4-21cc8f077795 + (do not change this comment) */ diff --git a/src/ioctl.h b/src/ioctl.h index 0366f6d6bd5..34f2a9aa644 100644 --- a/src/ioctl.h +++ b/src/ioctl.h @@ -1 +1,4 @@ /* Emacs ioctl emulation for VMS */ + +/* arch-tag: 48595931-af6e-407d-95c7-484059087767 + (do not change this comment) */ diff --git a/src/keyboard.c b/src/keyboard.c index f78c57715db..62017cec7b3 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1,5 +1,5 @@ /* Keyboard and mouse input; editor command loop. - Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99,2000,01,02,03 + Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99,2000,01,02,03,04 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -479,36 +479,6 @@ extern char *pending_malloc_warning; static struct input_event kbd_buffer[KBD_BUFFER_SIZE]; -/* Vector to GCPRO the Lisp objects referenced from kbd_buffer. - - The interrupt-level event handlers will never enqueue an event on a - frame which is not in Vframe_list, and once an event is dequeued, - internal_last_event_frame or the event itself points to the frame. - So that's all fine. - - But while the event is sitting in the queue, it's completely - unprotected. Suppose the user types one command which will run for - a while and then delete a frame, and then types another event at - the frame that will be deleted, before the command gets around to - it. Suppose there are no references to this frame elsewhere in - Emacs, and a GC occurs before the second event is dequeued. Now we - have an event referring to a freed frame, which will crash Emacs - when it is dequeued. - - Similar things happen when an event on a scroll bar is enqueued; the - window may be deleted while the event is in the queue. - - So, we use this vector to protect the Lisp_Objects in the event - queue. That way, they'll be dequeued as dead frames or windows, - but still valid Lisp objects. - - If kbd_buffer[i].kind != NO_EVENT, then - - AREF (kbd_buffer_gcpro, 2 * i) == kbd_buffer[i].frame_or_window. - AREF (kbd_buffer_gcpro, 2 * i + 1) == kbd_buffer[i].arg. */ - -static Lisp_Object kbd_buffer_gcpro; - /* Pointer to next available character in kbd_buffer. If kbd_fetch_ptr == kbd_store_ptr, the buffer is empty. This may be kbd_buffer + KBD_BUFFER_SIZE, meaning that the @@ -586,6 +556,8 @@ Lisp_Object Qvertical_line; Lisp_Object Qvertical_scroll_bar; Lisp_Object Qmenu_bar; extern Lisp_Object Qleft_margin, Qright_margin; +extern Lisp_Object Qleft_fringe, Qright_fringe; +extern Lisp_Object QCmap; Lisp_Object recursive_edit_unwind (), command_loop (); Lisp_Object Fthis_command_keys (); @@ -1957,7 +1929,12 @@ adjust_point_for_property (last_pt, modified) : (PT < last_pt ? beg : end)); check_composition = check_display = 1; } +#if 0 /* This assertion isn't correct, because SET_PT may end up setting + the point to something other than its argument, due to + point-motion hooks, intangibility, etc. */ xassert (PT == beg || PT == end); +#endif + /* Pretend the area doesn't exist if the buffer is not modified. */ if (!modified && !ellipsis && beg < end) @@ -2941,13 +2918,13 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) { Lisp_Object posn; - posn = POSN_BUFFER_POSN (EVENT_START (c)); + posn = POSN_POSN (EVENT_START (c)); /* Handle menu-bar events: insert the dummy prefix event `menu-bar'. */ if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar)) { /* Change menu-bar to (menu-bar) as the event "position". */ - POSN_BUFFER_SET_POSN (EVENT_START (c), Fcons (posn, Qnil)); + POSN_SET_POSN (EVENT_START (c), Fcons (posn, Qnil)); also_record = c; Vunread_command_events = Fcons (c, Vunread_command_events); @@ -3547,9 +3524,32 @@ void kbd_buffer_store_event (event) register struct input_event *event; { + kbd_buffer_store_event_hold (event, 0); +} + +/* Store EVENT obtained at interrupt level into kbd_buffer, fifo. + + If HOLD_QUIT is 0, just stuff EVENT into the fifo. + Else, if HOLD_QUIT.kind != NO_EVENT, discard EVENT. + Else, if EVENT is a quit event, store the quit event + in HOLD_QUIT, and return (thus ignoring further events). + + This is used in read_avail_input to postpone the processing + of the quit event until all subsequent input events have been + parsed (and discarded). + */ + +void +kbd_buffer_store_event_hold (event, hold_quit) + register struct input_event *event; + struct input_event *hold_quit; +{ if (event->kind == NO_EVENT) abort (); + if (hold_quit && hold_quit->kind != NO_EVENT) + return; + if (event->kind == ASCII_KEYSTROKE_EVENT) { register int c = event->code & 0377; @@ -3591,6 +3591,12 @@ kbd_buffer_store_event (event) } #endif + if (hold_quit) + { + bcopy (event, (char *) hold_quit, sizeof (*event)); + return; + } + /* If this results in a quit_char being returned to Emacs as input, set Vlast_event_frame properly. If this doesn't get returned to Emacs as an event, the next event read @@ -3620,7 +3626,9 @@ kbd_buffer_store_event (event) Just ignore the second one. */ else if (event->kind == BUFFER_SWITCH_EVENT && kbd_fetch_ptr != kbd_store_ptr - && kbd_store_ptr->kind == BUFFER_SWITCH_EVENT) + && ((kbd_store_ptr == kbd_buffer + ? kbd_buffer + KBD_BUFFER_SIZE - 1 + : kbd_store_ptr - 1)->kind) == BUFFER_SWITCH_EVENT) return; if (kbd_store_ptr - kbd_buffer == KBD_BUFFER_SIZE) @@ -3632,7 +3640,6 @@ kbd_buffer_store_event (event) Discard the event if it would fill the last slot. */ if (kbd_fetch_ptr - 1 != kbd_store_ptr) { - int idx; #if 0 /* The SELECTION_REQUEST_EVENT case looks bogus, and it's error prone to assign individual members for other events, in case @@ -3662,9 +3669,6 @@ kbd_buffer_store_event (event) *kbd_store_ptr = *event; #endif - idx = 2 * (kbd_store_ptr - kbd_buffer); - ASET (kbd_buffer_gcpro, idx, event->frame_or_window); - ASET (kbd_buffer_gcpro, idx + 1, event->arg); ++kbd_store_ptr; } } @@ -3683,24 +3687,22 @@ kbd_buffer_store_event (event) Value is the number of input_events generated. */ -int -gen_help_event (bufp, size, help, frame, window, object, pos) - struct input_event *bufp; - int size; +void +gen_help_event (help, frame, window, object, pos) Lisp_Object help, frame, object, window; int pos; { - if (size >= 1) - { - bufp->kind = HELP_EVENT; - bufp->frame_or_window = frame; - bufp->arg = object; - bufp->x = WINDOWP (window) ? window : frame; - bufp->y = help; - bufp->code = pos; - return 1; - } - return 0; + struct input_event event; + + EVENT_INIT (event); + + event.kind = HELP_EVENT; + event.frame_or_window = frame; + event.arg = object; + event.x = WINDOWP (window) ? window : frame; + event.y = help; + event.code = pos; + kbd_buffer_store_event (&event); } @@ -3780,9 +3782,6 @@ static INLINE void clear_event (event) struct input_event *event; { - int idx = 2 * (event - kbd_buffer); - ASET (kbd_buffer_gcpro, idx, Qnil); - ASET (kbd_buffer_gcpro, idx + 1, Qnil); event->kind = NO_EVENT; } @@ -4955,6 +4954,169 @@ EMACS_INT double_click_fuzz; int double_click_count; +/* Return position of a mouse click or wheel event */ + +static Lisp_Object +make_lispy_position (f, x, y, time) + struct frame *f; + Lisp_Object *x, *y; + unsigned long time; +{ + Lisp_Object window; + enum window_part part; + Lisp_Object posn = Qnil; + Lisp_Object extra_info = Qnil; + int wx, wy; + + /* Set `window' to the window under frame pixel coordinates (x,y) */ + if (f) + window = window_from_coordinates (f, XINT (*x), XINT (*y), + &part, &wx, &wy, 0); + else + window = Qnil; + + if (WINDOWP (window)) + { + /* It's a click in window window at frame coordinates (x,y) */ + struct window *w = XWINDOW (window); + Lisp_Object string_info = Qnil; + int textpos = -1, rx = -1, ry = -1; + int dx = -1, dy = -1; + int width = -1, height = -1; + Lisp_Object object = Qnil; + + /* Set event coordinates to window-relative coordinates + for constructing the Lisp event below. */ + XSETINT (*x, wx); + XSETINT (*y, wy); + + if (part == ON_MODE_LINE || part == ON_HEADER_LINE) + { + /* Mode line or header line. Look for a string under + the mouse that may have a `local-map' property. */ + Lisp_Object string; + int charpos; + + posn = part == ON_MODE_LINE ? Qmode_line : Qheader_line; + rx = wx, ry = wy; + string = mode_line_string (w, part, &rx, &ry, &charpos, + &object, &dx, &dy, &width, &height); + if (STRINGP (string)) + string_info = Fcons (string, make_number (charpos)); + if (w == XWINDOW (selected_window)) + textpos = PT; + else + textpos = XMARKER (w->pointm)->charpos; + } + else if (part == ON_VERTICAL_BORDER) + { + posn = Qvertical_line; + wx = -1; + dx = 0; + width = 1; + } + else if (part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN) + { + Lisp_Object string; + int charpos; + + posn = (part == ON_LEFT_MARGIN) ? Qleft_margin : Qright_margin; + rx = wx, ry = wy; + string = marginal_area_string (w, part, &rx, &ry, &charpos, + &object, &dx, &dy, &width, &height); + if (STRINGP (string)) + string_info = Fcons (string, make_number (charpos)); + } + else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE) + { + posn = (part == ON_LEFT_FRINGE) ? Qleft_fringe : Qright_fringe; + rx = 0; + dx = wx; + if (part == ON_RIGHT_FRINGE) + dx -= (window_box_width (w, LEFT_MARGIN_AREA) + + window_box_width (w, TEXT_AREA) + + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) + ? window_box_width (w, RIGHT_MARGIN_AREA) + : 0)); + else if (!WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)) + dx -= window_box_width (w, LEFT_MARGIN_AREA); + } + + if (textpos < 0) + { + Lisp_Object string2, object2 = Qnil; + struct display_pos p; + int dx2, dy2; + int width2, height2; + wx = max (WINDOW_LEFT_MARGIN_WIDTH (w), wx); + string2 = buffer_posn_from_coords (w, &wx, &wy, &p, + &object2, &dx2, &dy2, + &width2, &height2); + textpos = CHARPOS (p.pos); + if (rx < 0) rx = wx; + if (ry < 0) ry = wy; + if (dx < 0) dx = dx2; + if (dy < 0) dy = dy2; + if (width < 0) width = width2; + if (height < 0) height = height2; + + if (NILP (posn)) + { + posn = make_number (textpos); + if (STRINGP (string2)) + string_info = Fcons (string2, + make_number (CHARPOS (p.string_pos))); + } + if (NILP (object)) + object = object2; + } + +#ifdef HAVE_WINDOW_SYSTEM + if (IMAGEP (object)) + { + Lisp_Object image_map, hotspot; + if ((image_map = Fplist_get (XCDR (object), QCmap), + !NILP (image_map)) + && (hotspot = find_hot_spot (image_map, dx, dy), + CONSP (hotspot)) + && (hotspot = XCDR (hotspot), CONSP (hotspot))) + posn = XCAR (hotspot); + } +#endif + + /* Object info */ + extra_info = Fcons (object, + Fcons (Fcons (make_number (dx), + make_number (dy)), + Fcons (Fcons (make_number (width), + make_number (height)), + Qnil))); + + /* String info */ + extra_info = Fcons (string_info, + Fcons (make_number (textpos), + Fcons (Fcons (make_number (rx), + make_number (ry)), + extra_info))); + } + else if (f != 0) + { + XSETFRAME (window, f); + } + else + { + window = Qnil; + XSETFASTINT (*x, 0); + XSETFASTINT (*y, 0); + } + + return Fcons (window, + Fcons (posn, + Fcons (Fcons (*x, *y), + Fcons (make_number (time), + extra_info)))); +} + /* Given a struct input_event, build the lisp event which represents it. If EVENT is 0, build a mouse movement event from the mouse movement buffer, which should have a movement event in it. @@ -5089,25 +5251,23 @@ make_lispy_event (event) Lisp_Object position; Lisp_Object *start_pos_ptr; Lisp_Object start_pos; - Lisp_Object window; position = Qnil; /* Build the position as appropriate for this mouse click. */ if (event->kind == MOUSE_CLICK_EVENT) { - enum window_part part; struct frame *f = XFRAME (event->frame_or_window); - Lisp_Object posn; - Lisp_Object string_info = Qnil; +#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) int row, column; - int wx, wy; +#endif /* Ignore mouse events that were made on frame that have been deleted. */ if (! FRAME_LIVE_P (f)) return Qnil; +#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) /* EVENT->x and EVENT->y are frame-relative pixel coordinates at this place. Under old redisplay, COLUMN and ROW are set to frame relative glyph coordinates @@ -5116,7 +5276,6 @@ make_lispy_event (event) pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y), &column, &row, NULL, 1); -#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) /* In the non-toolkit version, clicks on the menu bar are ordinary button events in the event buffer. Distinguish them, and invoke the menu. @@ -5170,77 +5329,14 @@ make_lispy_event (event) } #endif /* not USE_X_TOOLKIT && not USE_GTK */ - /* Set `window' to the window under frame pixel coordinates - event->x/event->y. */ - window = window_from_coordinates (f, XINT (event->x), - XINT (event->y), - &part, &wx, &wy, 0); - - if (!WINDOWP (window)) - { - window = event->frame_or_window; - posn = Qnil; - } - else - { - /* It's a click in window window at frame coordinates - event->x/ event->y. */ - struct window *w = XWINDOW (window); - - /* Set event coordinates to window-relative coordinates - for constructing the Lisp event below. */ - XSETINT (event->x, wx); - XSETINT (event->y, wy); - - if (part == ON_MODE_LINE || part == ON_HEADER_LINE) - { - /* Mode line or header line. Look for a string under - the mouse that may have a `local-map' property. */ - Lisp_Object string; - int charpos; - - posn = part == ON_MODE_LINE ? Qmode_line : Qheader_line; - string = mode_line_string (w, wx, wy, part, &charpos); - if (STRINGP (string)) - string_info = Fcons (string, make_number (charpos)); - } - else if (part == ON_VERTICAL_BORDER) - posn = Qvertical_line; - else if (part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN) - { - int charpos; - Lisp_Object object = marginal_area_string (w, wx, wy, part, - &charpos); - posn = (part == ON_LEFT_MARGIN) ? Qleft_margin : Qright_margin; - if (STRINGP (object)) - string_info = Fcons (object, make_number (charpos)); - } - else - { - Lisp_Object object; - struct display_pos p; - buffer_posn_from_coords (w, &wx, &wy, &object, &p); - posn = make_number (CHARPOS (p.pos)); - if (STRINGP (object)) - string_info - = Fcons (object, - make_number (CHARPOS (p.string_pos))); - } - } - - position - = Fcons (window, - Fcons (posn, - Fcons (Fcons (event->x, event->y), - Fcons (make_number (event->timestamp), - (NILP (string_info) - ? Qnil - : Fcons (string_info, Qnil)))))); + position = make_lispy_position (f, &event->x, &event->y, + event->timestamp); } #ifndef USE_TOOLKIT_SCROLL_BARS else { /* It's a scrollbar click. */ + Lisp_Object window; Lisp_Object portion_whole; Lisp_Object part; @@ -5405,97 +5501,18 @@ make_lispy_event (event) case WHEEL_EVENT: { Lisp_Object position; - Lisp_Object window; Lisp_Object head; - + /* Build the position as appropriate for this mouse click. */ - enum window_part part; struct frame *f = XFRAME (event->frame_or_window); - Lisp_Object posn; - Lisp_Object string_info = Qnil; - int row, column; - int wx, wy; - position = Qnil; /* Ignore wheel events that were made on frame that have been deleted. */ if (! FRAME_LIVE_P (f)) return Qnil; - /* EVENT->x and EVENT->y are frame-relative pixel - coordinates at this place. Under old redisplay, COLUMN - and ROW are set to frame relative glyph coordinates - which are then used to determine whether this click is - in a menu (non-toolkit version). */ - pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y), - &column, &row, NULL, 1); - - /* Set `window' to the window under frame pixel coordinates - event->x/event->y. */ - window = window_from_coordinates (f, XINT (event->x), - XINT (event->y), - &part, &wx, &wy, 0); - - if (!WINDOWP (window)) - { - window = event->frame_or_window; - posn = Qnil; - } - else - { - /* It's a click in window window at frame coordinates - event->x/ event->y. */ - struct window *w = XWINDOW (window); - - /* Set event coordinates to window-relative coordinates - for constructing the Lisp event below. */ - XSETINT (event->x, wx); - XSETINT (event->y, wy); - - if (part == ON_MODE_LINE || part == ON_HEADER_LINE) - { - /* Mode line or header line. Look for a string under - the mouse that may have a `local-map' property. */ - Lisp_Object string; - int charpos; - - posn = part == ON_MODE_LINE ? Qmode_line : Qheader_line; - string = mode_line_string (w, wx, wy, part, &charpos); - if (STRINGP (string)) - string_info = Fcons (string, make_number (charpos)); - } - else if (part == ON_VERTICAL_BORDER) - posn = Qvertical_line; - else if (part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN) - { - int charpos; - Lisp_Object object = marginal_area_string (w, wx, wy, part, - &charpos); - posn = (part == ON_LEFT_MARGIN) ? Qleft_margin : Qright_margin; - if (STRINGP (object)) - string_info = Fcons (object, make_number (charpos)); - } - else - { - Lisp_Object object; - struct display_pos p; - buffer_posn_from_coords (w, &wx, &wy, &object, &p); - posn = make_number (CHARPOS (p.pos)); - if (STRINGP (object)) - string_info - = Fcons (object, - make_number (CHARPOS (p.string_pos))); - } - } - - position - = Fcons (window, - Fcons (posn, - Fcons (Fcons (event->x, event->y), - Fcons (make_number (event->timestamp), - (NILP (string_info) - ? Qnil - : Fcons (string_info, Qnil)))))); + position = make_lispy_position (f, &event->x, &event->y, + event->timestamp); /* Set double or triple modifiers to indicate the wheel speed. */ { @@ -5689,12 +5706,9 @@ make_lispy_event (event) case DRAG_N_DROP_EVENT: { - enum window_part part; FRAME_PTR f; - Lisp_Object window; - Lisp_Object posn; + Lisp_Object head, position; Lisp_Object files; - int wx, wy; /* The frame_or_window field should be a cons of the frame in which the event occurred and a list of the filenames @@ -5710,60 +5724,17 @@ make_lispy_event (event) if (! FRAME_LIVE_P (f)) return Qnil; - window = window_from_coordinates (f, XINT (event->x), - XINT (event->y), - &part, &wx, &wy, 0); - - if (!WINDOWP (window)) - { - window = XCAR (event->frame_or_window); - posn = Qnil; - } - else - { - /* It's an event in window `window' at frame coordinates - event->x/ event->y. */ - struct window *w = XWINDOW (window); - - /* Set event coordinates to window-relative coordinates - for constructing the Lisp event below. */ - XSETINT (event->x, wx); - XSETINT (event->y, wy); - - if (part == ON_MODE_LINE) - posn = Qmode_line; - else if (part == ON_VERTICAL_BORDER) - posn = Qvertical_line; - else if (part == ON_HEADER_LINE) - posn = Qheader_line; - else - { - Lisp_Object object; - struct display_pos p; - buffer_posn_from_coords (w, &wx, &wy, &object, &p); - posn = make_number (CHARPOS (p.pos)); - } - } - - { - Lisp_Object head, position; - - position - = Fcons (window, - Fcons (posn, - Fcons (Fcons (event->x, event->y), - Fcons (make_number (event->timestamp), - Qnil)))); - - head = modify_event_symbol (0, event->modifiers, - Qdrag_n_drop, Qnil, - lispy_drag_n_drop_names, - &drag_n_drop_syms, 1); - return Fcons (head, - Fcons (position, - Fcons (files, - Qnil))); - } + position = make_lispy_position (f, &event->x, &event->y, + event->timestamp); + + head = modify_event_symbol (0, event->modifiers, + Qdrag_n_drop, Qnil, + lispy_drag_n_drop_names, + &drag_n_drop_syms, 1); + return Fcons (head, + Fcons (position, + Fcons (files, + Qnil))); } #endif /* HAVE_MOUSE */ @@ -5836,59 +5807,12 @@ make_lispy_movement (frame, bar_window, part, x, y, time) /* Or is it an ordinary mouse movement? */ else { - enum window_part area; - Lisp_Object window; - Lisp_Object posn; - int wx, wy; + Lisp_Object position; - if (frame) - /* It's in a frame; which window on that frame? */ - window = window_from_coordinates (frame, XINT (x), XINT (y), - &area, &wx, &wy, 0); - else - window = Qnil; - - if (WINDOWP (window)) - { - struct window *w = XWINDOW (window); - - /* Set window relative coordinates. */ - XSETINT (x, wx); - XSETINT (y, wy); - - if (area == ON_MODE_LINE) - posn = Qmode_line; - else if (area == ON_VERTICAL_BORDER) - posn = Qvertical_line; - else if (area == ON_HEADER_LINE) - posn = Qheader_line; - else - { - Lisp_Object object; - struct display_pos p; - buffer_posn_from_coords (w, &wx, &wy, &object, &p); - posn = make_number (CHARPOS (p.pos)); - } - } - else if (frame != 0) - { - XSETFRAME (window, frame); - posn = Qnil; - } - else - { - window = Qnil; - posn = Qnil; - XSETFASTINT (x, 0); - XSETFASTINT (y, 0); - } + position = make_lispy_position (frame, &x, &y, time); return Fcons (Qmouse_movement, - Fcons (Fcons (window, - Fcons (posn, - Fcons (Fcons (x, y), - Fcons (make_number (time), - Qnil)))), + Fcons (position, Qnil)); } } @@ -6126,7 +6050,7 @@ parse_modifiers (symbol) SBYTES (SYMBOL_NAME (symbol)) - end), Qnil); - if (modifiers & ~VALMASK) + if (modifiers & ~INTMASK) abort (); XSETFASTINT (mask, modifiers); elements = Fcons (unmodified, Fcons (mask, Qnil)); @@ -6163,7 +6087,7 @@ apply_modifiers (modifiers, base) Lisp_Object cache, index, entry, new_symbol; /* Mask out upper bits. We don't know where this value's been. */ - modifiers &= VALMASK; + modifiers &= INTMASK; /* The click modifier never figures into cache indices. */ cache = Fget (base, Qmodifier_cache); @@ -6684,16 +6608,27 @@ static int read_avail_input (expected) int expected; { - struct input_event buf[KBD_BUFFER_SIZE]; register int i; - int nread; - - for (i = 0; i < KBD_BUFFER_SIZE; i++) - EVENT_INIT (buf[i]); + int nread = 0; if (read_socket_hook) - /* No need for FIONREAD or fcntl; just say don't wait. */ - nread = (*read_socket_hook) (input_fd, buf, KBD_BUFFER_SIZE, expected); + { + int discard = 0; + int nr; + struct input_event hold_quit; + + EVENT_INIT (hold_quit); + hold_quit.kind = NO_EVENT; + + /* No need for FIONREAD or fcntl; just say don't wait. */ + while (nr = (*read_socket_hook) (input_fd, expected, &hold_quit), nr > 0) + { + nread += nr; + expected = 0; + } + if (hold_quit.kind != NO_EVENT) + kbd_buffer_store_event (&hold_quit); + } else { /* Using KBD_BUFFER_SIZE - 1 here avoids reading more than @@ -6794,34 +6729,56 @@ read_avail_input (expected) #endif /* no FIONREAD */ for (i = 0; i < nread; i++) { - buf[i].kind = ASCII_KEYSTROKE_EVENT; - buf[i].modifiers = 0; + struct input_event buf; + EVENT_INIT (buf); + buf.kind = ASCII_KEYSTROKE_EVENT; + buf.modifiers = 0; if (meta_key == 1 && (cbuf[i] & 0x80)) - buf[i].modifiers = meta_modifier; + buf.modifiers = meta_modifier; if (meta_key != 2) cbuf[i] &= ~0x80; - buf[i].code = cbuf[i]; - buf[i].frame_or_window = selected_frame; - buf[i].arg = Qnil; - } - } + buf.code = cbuf[i]; + buf.frame_or_window = selected_frame; + buf.arg = Qnil; - /* Scan the chars for C-g and store them in kbd_buffer. */ - for (i = 0; i < nread; i++) - { - kbd_buffer_store_event (&buf[i]); - /* Don't look at input that follows a C-g too closely. - This reduces lossage due to autorepeat on C-g. */ - if (buf[i].kind == ASCII_KEYSTROKE_EVENT - && buf[i].code == quit_char) - break; + kbd_buffer_store_event (&buf); + /* Don't look at input that follows a C-g too closely. + This reduces lossage due to autorepeat on C-g. */ + if (buf.kind == ASCII_KEYSTROKE_EVENT + && buf.code == quit_char) + break; + } } return nread; } #endif /* not VMS */ +void +handle_async_input () +{ +#ifdef BSD4_1 + extern int select_alarmed; +#endif + interrupt_input_pending = 0; + + while (1) + { + int nread; + nread = read_avail_input (1); + /* -1 means it's not ok to read the input now. + UNBLOCK_INPUT will read it later; now, avoid infinite loop. + 0 means there was no keyboard input available. */ + if (nread <= 0) + break; + +#ifdef BSD4_1 + select_alarmed = 1; /* Force the select emulator back to life */ +#endif + } +} + #ifdef SIGIO /* for entire page */ /* Note SIGIO has been undef'd if FIONREAD is missing. */ @@ -6831,9 +6788,6 @@ input_available_signal (signo) { /* Must preserve main program's value of errno. */ int old_errno = errno; -#ifdef BSD4_1 - extern int select_alarmed; -#endif #if defined (USG) && !defined (POSIX_SIGNALS) /* USG systems forget handlers when they are used; @@ -6848,20 +6802,11 @@ input_available_signal (signo) if (input_available_clear_time) EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0); - while (1) - { - int nread; - nread = read_avail_input (1); - /* -1 means it's not ok to read the input now. - UNBLOCK_INPUT will read it later; now, avoid infinite loop. - 0 means there was no keyboard input available. */ - if (nread <= 0) - break; - -#ifdef BSD4_1 - select_alarmed = 1; /* Force the select emulator back to life */ +#ifdef SYNC_INPUT + interrupt_input_pending = 1; +#else + handle_async_input (); #endif - } #ifdef BSD4_1 sigfree (); @@ -6880,7 +6825,7 @@ void reinvoke_input_signal () { #ifdef SIGIO - kill (getpid (), SIGIO); + handle_async_input (); #endif } @@ -8338,7 +8283,7 @@ access_keymap_keyremap (map, key, prompt, do_funcall) int do_funcall; { Lisp_Object next; - + next = access_keymap (map, key, 1, 0, 1); /* Handle symbol with autoload definition. */ @@ -8353,7 +8298,7 @@ access_keymap_keyremap (map, key, prompt, do_funcall) && (!NILP (Farrayp (XSYMBOL (next)->function)) || KEYMAPP (XSYMBOL (next)->function))) next = XSYMBOL (next)->function; - + /* If the keymap gives a function, not an array, then call the function with one arg and use its value instead. */ @@ -8935,6 +8880,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, if (EVENT_HAS_PARAMETERS (key)) { Lisp_Object kind; + Lisp_Object string; kind = EVENT_HEAD_KIND (EVENT_HEAD (key)); if (EQ (kind, Qmouse_click)) @@ -8942,7 +8888,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, Lisp_Object window, posn; window = POSN_WINDOW (EVENT_START (key)); - posn = POSN_BUFFER_POSN (EVENT_START (key)); + posn = POSN_POSN (EVENT_START (key)); if (CONSP (posn) || (!NILP (fake_prefixed_keys) @@ -9000,7 +8946,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, localized_local_map = 1; start = EVENT_START (key); - if (CONSP (start) && CONSP (XCDR (start))) + if (CONSP (start) && POSN_INBUFFER_P (start)) { pos = POSN_BUFFER_POSN (start); if (INTEGERP (pos) @@ -9051,11 +8997,11 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, /* If on a mode line string with a local keymap, reconsider the key sequence with that keymap. */ - if (CONSP (POSN_STRING (EVENT_START (key)))) + if (string = POSN_STRING (EVENT_START (key)), + (CONSP (string) && STRINGP (XCAR (string)))) { - Lisp_Object string, pos, map, map2; + Lisp_Object pos, map, map2; - string = POSN_STRING (EVENT_START (key)); pos = XCDR (string); string = XCAR (string); if (XINT (pos) >= 0 @@ -9074,16 +9020,16 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, goto replay_key; } - else if (CONSP (POSN_STRING (EVENT_START (key))) - && NILP (from_string)) + else if (NILP (from_string) + && (string = POSN_STRING (EVENT_START (key)), + (CONSP (string) && STRINGP (XCAR (string))))) { /* For a click on a string, i.e. overlay string or a string displayed via the `display' property, consider `local-map' and `keymap' properties of that string. */ - Lisp_Object string, pos, map, map2; + Lisp_Object pos, map, map2; - string = POSN_STRING (EVENT_START (key)); pos = XCDR (string); string = XCAR (string); if (XINT (pos) >= 0 @@ -9110,7 +9056,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, { Lisp_Object posn; - posn = POSN_BUFFER_POSN (EVENT_START (key)); + posn = POSN_POSN (EVENT_START (key)); /* Handle menu-bar events: insert the dummy prefix event `menu-bar'. */ if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar)) @@ -9122,8 +9068,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, /* Zap the position in key, so we know that we've expanded it, and don't try to do so again. */ - POSN_BUFFER_SET_POSN (EVENT_START (key), - Fcons (posn, Qnil)); + POSN_SET_POSN (EVENT_START (key), + Fcons (posn, Qnil)); mock_input = t + 2; goto replay_sequence; @@ -9366,7 +9312,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, /* Adjust the function-key-map counters. */ fkey.end += diff; fkey.start += diff; - + goto replay_sequence; } } @@ -10134,7 +10080,6 @@ Also end any kbd macro being defined. */) discard_tty_input (); kbd_fetch_ptr = kbd_store_ptr; - Ffillarray (kbd_buffer_gcpro, Qnil); input_pending = 0; return Qnil; @@ -10225,17 +10170,13 @@ stuff_buffered_input (stuffstring) Should we ignore anything that was typed in at the "wrong" kboard? */ for (; kbd_fetch_ptr != kbd_store_ptr; kbd_fetch_ptr++) { - int idx; if (kbd_fetch_ptr == kbd_buffer + KBD_BUFFER_SIZE) kbd_fetch_ptr = kbd_buffer; if (kbd_fetch_ptr->kind == ASCII_KEYSTROKE_EVENT) stuff_char (kbd_fetch_ptr->code); - kbd_fetch_ptr->kind = NO_EVENT; - idx = 2 * (kbd_fetch_ptr - kbd_buffer); - ASET (kbd_buffer_gcpro, idx, Qnil); - ASET (kbd_buffer_gcpro, idx + 1, Qnil); + clear_event (kbd_fetch_ptr); } input_pending = 0; @@ -10635,7 +10576,6 @@ init_keyboard () recent_keys_index = 0; kbd_fetch_ptr = kbd_buffer; kbd_store_ptr = kbd_buffer; - kbd_buffer_gcpro = Fmake_vector (make_number (2 * KBD_BUFFER_SIZE), Qnil); #ifdef HAVE_MOUSE do_mouse_tracking = Qnil; #endif @@ -10926,9 +10866,6 @@ syms_of_keyboard () Fset (Qextended_command_history, Qnil); staticpro (&Qextended_command_history); - kbd_buffer_gcpro = Fmake_vector (make_number (2 * KBD_BUFFER_SIZE), Qnil); - staticpro (&kbd_buffer_gcpro); - accent_key_syms = Qnil; staticpro (&accent_key_syms); @@ -11382,7 +11319,7 @@ keys_of_keyboard () /* Handling it at such a low-level causes read_key_sequence to get * confused because it doesn't realize that the current_buffer was * changed by read_char. - * + * * initial_define_lispy_key (Vspecial_event_map, "select-window", * "handle-select-window"); */ initial_define_lispy_key (Vspecial_event_map, "save-session", @@ -11427,3 +11364,6 @@ mark_kboards () } } } + +/* arch-tag: 774e34d7-6d31-42f3-8397-e079a4e4c9ca + (do not change this comment) */ diff --git a/src/keyboard.h b/src/keyboard.h index 9d77d21ec75..d92f13a5059 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -250,21 +250,25 @@ extern Lisp_Object item_properties; #define EVENT_END(event) (XCAR (XCDR (XCDR (event)))) /* Extract the click count from a multi-click event. */ -#define EVENT_CLICK_COUNT(event) (Fnth ((event), make_number (2))) +#define EVENT_CLICK_COUNT(event) (Fnth (make_number (2), (event))) /* Extract the fields of a position. */ #define POSN_WINDOW(posn) (XCAR (posn)) -#define POSN_BUFFER_POSN(posn) (XCAR (XCDR (posn))) -#define POSN_BUFFER_SET_POSN(posn,x) (XSETCAR (XCDR (posn), (x))) +#define POSN_POSN(posn) (XCAR (XCDR (posn))) +#define POSN_SET_POSN(posn,x) (XSETCAR (XCDR (posn), (x))) #define POSN_WINDOW_POSN(posn) (XCAR (XCDR (XCDR (posn)))) -#define POSN_TIMESTAMP(posn) \ - (XCAR (XCDR (XCDR (XCDR (posn))))) -#define POSN_SCROLLBAR_PART(posn) (Fnth ((posn), make_number (4))) +#define POSN_TIMESTAMP(posn) (XCAR (XCDR (XCDR (XCDR (posn))))) +#define POSN_SCROLLBAR_PART(posn) (Fnth (make_number (4), (posn))) /* A cons (STRING . STRING-CHARPOS), or nil in mouse-click events. It's a cons if the click is over a string in the mode line. */ -#define POSN_STRING(POSN) Fnth (make_number (4), (POSN)) +#define POSN_STRING(posn) (Fnth (make_number (4), (posn))) + +/* If POSN_STRING is nil, event refers to buffer location. */ + +#define POSN_INBUFFER_P(posn) (NILP (POSN_STRING (posn))) +#define POSN_BUFFER_POSN(posn) (Fnth (make_number (5), (posn))) /* Some of the event heads. */ extern Lisp_Object Qswitch_frame; @@ -325,13 +329,18 @@ extern void timer_start_idle P_ ((void)); extern void timer_stop_idle P_ ((void)); extern int lucid_event_type_list_p P_ ((Lisp_Object)); extern void kbd_buffer_store_event P_ ((struct input_event *)); +extern void kbd_buffer_store_event_hold P_ ((struct input_event *, + struct input_event *)); #ifdef POLL_FOR_INPUT extern void poll_for_input_1 P_ ((void)); #endif extern void show_help_echo P_ ((Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, int)); -extern int gen_help_event P_ ((struct input_event *, int, Lisp_Object, - Lisp_Object, Lisp_Object, Lisp_Object, int)); +extern void gen_help_event P_ ((Lisp_Object, Lisp_Object, Lisp_Object, + Lisp_Object, int)); extern void kbd_buffer_store_help_event P_ ((Lisp_Object, Lisp_Object)); extern Lisp_Object menu_item_eval_property P_ ((Lisp_Object)); extern int kbd_buffer_events_waiting P_ ((int)); + +/* arch-tag: 769cbade-1ba9-4950-b886-db265b061aa3 + (do not change this comment) */ diff --git a/src/keymap.c b/src/keymap.c index 7fa4d9a6f71..62ea237b85c 100644 --- a/src/keymap.c +++ b/src/keymap.c @@ -1,5 +1,5 @@ /* Manipulation of keymaps - Copyright (C) 1985, 86,87,88,93,94,95,98,99, 2000, 2001 + Copyright (C) 1985, 86,87,88,93,94,95,98,99, 2000, 01, 2004 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -672,7 +672,6 @@ map_keymap (map, fun, args, data, autoload) /* Loop over the char values represented in the vector. */ int len = ASIZE (binding); int c; - abort(); for (c = 0; c < len; c++) { Lisp_Object character; @@ -2312,7 +2311,7 @@ shadow_lookup (shadow, key, flag) return Qnil; } -static Lisp_Object Vmenu_events; +static Lisp_Object Vmouse_events; /* This function can GC if Flookup_key autoloads any keymaps. */ @@ -2369,7 +2368,7 @@ where_is_internal (definition, keymaps, firstonly, noindirect, no_remap) /* if (nomenus && !ascii_sequence_p (this)) */ if (nomenus && XINT (last) >= 0 && SYMBOLP (tem = Faref (this, make_number (0))) - && !NILP (Fmemq (XCAR (parse_modifiers (tem)), Vmenu_events))) + && !NILP (Fmemq (XCAR (parse_modifiers (tem)), Vmouse_events))) /* If no menu entries should be returned, skip over the keymaps bound to `menu-bar' and `tool-bar' and other non-ascii prefixes like `C-down-mouse-2'. */ @@ -3551,13 +3550,17 @@ This keymap works like `function-key-map', but comes after that, and applies even for keys that have ordinary bindings. */); Vkey_translation_map = Qnil; - staticpro (&Vmenu_events); - Vmenu_events = Fcons (intern ("menu-bar"), - Fcons (intern ("tool-bar"), - Fcons (intern ("mouse-1"), - Fcons (intern ("mouse-2"), - Fcons (intern ("mouse-3"), - Qnil))))); + staticpro (&Vmouse_events); + Vmouse_events = Fcons (intern ("menu-bar"), + Fcons (intern ("tool-bar"), + Fcons (intern ("header-line"), + Fcons (intern ("mode-line"), + Fcons (intern ("mouse-1"), + Fcons (intern ("mouse-2"), + Fcons (intern ("mouse-3"), + Fcons (intern ("mouse-4"), + Fcons (intern ("mouse-5"), + Qnil))))))))); Qsingle_key_description = intern ("single-key-description"); @@ -3624,3 +3627,6 @@ keys_of_keymap () initial_define_key (global_map, 033, "ESC-prefix"); initial_define_key (global_map, Ctl('X'), "Control-X-prefix"); } + +/* arch-tag: 6dd15c26-7cf1-41c4-b904-f42f7ddda463 + (do not change this comment) */ diff --git a/src/keymap.h b/src/keymap.h index 39265fe865e..2a34061593f 100644 --- a/src/keymap.h +++ b/src/keymap.h @@ -52,3 +52,6 @@ typedef void (*map_keymap_function_t) extern void map_keymap P_ ((Lisp_Object map, map_keymap_function_t fun, Lisp_Object largs, void* cargs, int autoload)); #endif + +/* arch-tag: 7400d5a1-ef0b-43d0-b366-f4d678bf3ba2 + (do not change this comment) */ diff --git a/src/lastfile.c b/src/lastfile.c index e93bbc6c6ab..df678b42876 100644 --- a/src/lastfile.c +++ b/src/lastfile.c @@ -40,7 +40,7 @@ Boston, MA 02111-1307, USA. */ char my_edata[] = "End of Emacs initialized data"; -#ifdef WINDOWSNT +#if defined(WINDOWSNT) || defined(CYGWIN) /* Help unexec locate the end of the .bss area used by Emacs (which isn't always a separate section in NT executables). */ char my_endbss[1]; @@ -51,3 +51,6 @@ char my_endbss[1]; static char _my_endbss[1]; char * my_endbss_static = _my_endbss; #endif + +/* arch-tag: 67e81ab4-e14f-44b2-8875-c0c12252223e + (do not change this comment) */ diff --git a/src/lisp.h b/src/lisp.h index 0a3fd96584b..6f248df0a3c 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -1,5 +1,5 @@ /* Fundamental definitions for GNU Emacs Lisp interpreter. - Copyright (C) 1985,86,87,93,94,95,97,98,1999,2000, 2001, 2002, 2003 + Copyright (C) 1985,86,87,93,94,95,97,98,1999,2000,01,02,03,2004 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -19,6 +19,9 @@ 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. */ +#ifndef EMACS_LISP_H +#define EMACS_LISP_H + /* Declare the prototype for a general external function. */ #if defined (PROTOTYPES) || defined (WINDOWSNT) #define P_(proto) proto @@ -64,10 +67,6 @@ extern void die P_((const char *, const char *, int)); ? (void) 0 \ : die ((msg), __FILE__, __LINE__)), \ 0) - -/* Let's get some compile-time checking too. */ -#undef NO_UNION_TYPE - #else /* Produce same side effects and result, but don't complain. */ @@ -160,8 +159,7 @@ enum Lisp_Misc_Type /* These values are overridden by the m- file on some machines. */ #ifndef VALBITS -/* The -1 is for the markbit. */ -#define VALBITS (BITS_PER_EMACS_INT - GCTYPEBITS - 1) +#define VALBITS (BITS_PER_EMACS_INT - GCTYPEBITS) #endif #ifndef NO_UNION_TYPE @@ -180,21 +178,13 @@ union Lisp_Object struct { EMACS_INT val : VALBITS; - EMACS_INT type : GCTYPEBITS + 1; + enum Lisp_Type type : GCTYPEBITS; } s; struct { EMACS_UINT val : VALBITS; - EMACS_INT type : GCTYPEBITS + 1; + enum Lisp_Type type : GCTYPEBITS; } u; - struct - { - EMACS_UINT val : VALBITS; - enum Lisp_Type type : GCTYPEBITS; - /* The markbit is not really part of the value of a Lisp_Object, - and is always zero except during garbage collection. */ - EMACS_UINT markbit : 1; - } gu; } Lisp_Object; @@ -209,22 +199,14 @@ union Lisp_Object struct { - EMACS_INT type : GCTYPEBITS+1; + enum Lisp_Type type : GCTYPEBITS; EMACS_INT val : VALBITS; } s; struct { - EMACS_INT type : GCTYPEBITS+1; + enum Lisp_Type type : GCTYPEBITS; EMACS_UINT val : VALBITS; } u; - struct - { - /* The markbit is not really part of the value of a Lisp_Object, - and is always zero except during garbage collection. */ - EMACS_UINT markbit : 1; - enum Lisp_Type type : GCTYPEBITS; - EMACS_UINT val : VALBITS; - } gu; } Lisp_Object; @@ -254,25 +236,13 @@ LISP_MAKE_RVALUE (Lisp_Object o) #define LISP_MAKE_RVALUE(o) (0+(o)) #endif /* NO_UNION_TYPE */ -#ifndef VALMASK -#define VALMASK ((((EMACS_INT) 1)<<VALBITS) - 1) -#endif -#define GCTYPEMASK ((((EMACS_INT) 1)<<GCTYPEBITS) - 1) - /* Two flags that are set during GC. On some machines, these flags are defined differently by the m- file. */ -/* This is set in the car of a cons to indicate it is marked. - Likewise in the type slot of a float and in the size slot of strings. */ - -#ifndef MARKBIT -#define MARKBIT ((EMACS_INT) ((EMACS_UINT) 1 << (VALBITS + GCTYPEBITS))) -#endif /*MARKBIT */ - /* In the size word of a vector, this bit means the vector has been marked. */ #ifndef ARRAY_MARK_FLAG -#define ARRAY_MARK_FLAG ((MARKBIT >> 1) & ~MARKBIT) +#define ARRAY_MARK_FLAG ((EMACS_INT) ((EMACS_UINT) 1 << (VALBITS + GCTYPEBITS - 1))) #endif /* no ARRAY_MARK_FLAG */ /* In the size word of a struct Lisp_Vector, this bit means it's really @@ -310,38 +280,74 @@ enum pvec_type /* For convenience, we also store the number of elements in these bits. */ #define PSEUDOVECTOR_SIZE_MASK 0x1ff +/***** Select the tagging scheme. *****/ + +/* First, try and define DECL_ALIGN(type,var) which declares a static + variable VAR of type TYPE with the added requirement that it be + TYPEBITS-aligned. */ +#if defined USE_LSB_TAG && !defined DECL_ALIGN +/* What compiler directive should we use for non-gcc compilers? -stef */ +# if defined (__GNUC__) +# define DECL_ALIGN(type, var) \ + type __attribute__ ((__aligned__ (1 << GCTYPEBITS))) var +# else +# error "USE_LSB_TAG used without defining DECL_ALIGN" +# endif +#endif + +#ifndef USE_LSB_TAG +/* Just remove the alignment annotation if we don't use it. */ +#undef DECL_ALIGN +#define DECL_ALIGN(type, var) type var +#endif + + /* These macros extract various sorts of values from a Lisp_Object. For example, if tem is a Lisp_Object whose type is Lisp_Cons, XCONS (tem) is the struct Lisp_Cons * pointing to the memory for that cons. */ #ifdef NO_UNION_TYPE +#ifdef USE_LSB_TAG + +#define TYPEMASK ((((EMACS_INT) 1) << GCTYPEBITS) - 1) +#define XTYPE(a) ((enum Lisp_Type) (((EMACS_UINT) (a)) & TYPEMASK)) +#define XINT(a) (((EMACS_INT) (a)) >> GCTYPEBITS) +#define XUINT(a) (((EMACS_UINT) (a)) >> GCTYPEBITS) +#define XSET(var, type, ptr) \ + (eassert (XTYPE (ptr) == 0), /* Check alignment. */ \ + (var) = ((EMACS_INT) (type)) | ((EMACS_INT) (ptr))) +#define make_number(N) (((EMACS_INT) (N)) << GCTYPEBITS) + +/* XFASTINT and XSETFASTINT are for use when the integer is known to be + positive, in which case the implementation can sometimes be faster + depending on the tagging scheme. With USE_LSB_TAG, there's no benefit. */ +#define XFASTINT(a) XINT (a) +#define XSETFASTINT(a, b) ((a) = make_number (b)) + +#define XPNTR(a) ((EMACS_INT) ((a) & ~TYPEMASK)) + +#else /* not USE_LSB_TAG */ + +#define VALMASK ((((EMACS_INT) 1) << VALBITS) - 1) + /* One need to override this if there must be high bits set in data space (doing the result of the below & ((1 << (GCTYPE + 1)) - 1) would work on all machines, but would penalize machines which don't need it) */ -#ifndef XTYPE -#define XTYPE(a) ((enum Lisp_Type) ((a) >> VALBITS)) -#endif - -#ifndef XSETTYPE -#define XSETTYPE(a, b) ((a) = XUINT (a) | ((EMACS_INT)(b) << VALBITS)) -#endif +#define XTYPE(a) ((enum Lisp_Type) (((EMACS_UINT) (a)) >> VALBITS)) /* For integers known to be positive, XFASTINT provides fast retrieval and XSETFASTINT provides fast storage. This takes advantage of the - fact that Lisp_Int is 0. - Beware: XFASTINT applied to a non-positive integer or to something - else than an integer should return something that preserves all the - info that was in the Lisp_Object, because it is used in EQ. */ + fact that Lisp_Int is 0. */ #define XFASTINT(a) ((a) + 0) #define XSETFASTINT(a, b) ((a) = (b)) /* Extract the value of a Lisp_Object as a signed integer. */ #ifndef XINT /* Some machines need to do this differently. */ -#define XINT(a) ((EMACS_INT) (((a) << (BITS_PER_EMACS_INT - VALBITS)) \ - >> (BITS_PER_EMACS_INT - VALBITS))) +#define XINT(a) ((((EMACS_INT) (a)) << (BITS_PER_EMACS_INT - VALBITS)) \ + >> (BITS_PER_EMACS_INT - VALBITS)) #endif /* Extract the value as an unsigned integer. This is a basis @@ -361,41 +367,13 @@ enum pvec_type #define make_number(N) \ ((((EMACS_INT) (N)) & VALMASK) | ((EMACS_INT) Lisp_Int) << VALBITS) -/* During garbage collection, XGCTYPE must be used for extracting types - so that the mark bit is ignored. XMARKBIT accesses the markbit. - Markbits are used only in particular slots of particular structure types. - Other markbits are always zero. - Outside of garbage collection, all mark bits are always zero. */ - -#ifndef XGCTYPE -#define XGCTYPE(a) ((enum Lisp_Type) (((a) >> VALBITS) & GCTYPEMASK)) -#endif - -#if VALBITS + GCTYPEBITS == BITS_PER_EMACS_INT - 1 -/* Make XMARKBIT faster if mark bit is sign bit. */ -#ifndef XMARKBIT -#define XMARKBIT(a) ((a) < 0) -#endif -#endif /* markbit is sign bit */ - -#ifndef XMARKBIT -#define XMARKBIT(a) ((a) & MARKBIT) -#endif - -#ifndef XMARK -#define XMARK(a) ((a) |= MARKBIT) -#endif +#endif /* not USE_LSB_TAG */ -#ifndef XUNMARK -#define XUNMARK(a) ((a) &= ~MARKBIT) -#endif +#define EQ(x, y) ((x) == (y)) -#endif /* NO_UNION_TYPE */ - -#ifndef NO_UNION_TYPE +#else /* not NO_UNION_TYPE */ #define XTYPE(a) ((enum Lisp_Type) (a).u.type) -#define XSETTYPE(a, b) ((a).u.type = (char) (b)) /* For integers known to be positive, XFASTINT provides fast retrieval and XSETFASTINT provides fast storage. This takes advantage of the @@ -423,18 +401,20 @@ enum pvec_type extern Lisp_Object make_number (); #endif +#define EQ(x, y) ((x).s.val == (y).s.val) + +#endif /* NO_UNION_TYPE */ + /* During garbage collection, XGCTYPE must be used for extracting types - so that the mark bit is ignored. XMARKBIT access the markbit. + so that the mark bit is ignored. XMARKBIT accesses the markbit. Markbits are used only in particular slots of particular structure types. Other markbits are always zero. Outside of garbage collection, all mark bits are always zero. */ -#define XGCTYPE(a) ((a).gu.type) -#define XMARKBIT(a) ((a).gu.markbit) -#define XMARK(a) (XMARKBIT(a) = 1) -#define XUNMARK(a) (XMARKBIT(a) = 0) - -#endif /* NO_UNION_TYPE */ +#ifndef XGCTYPE +/* The distinction does not exist now that the MARKBIT has been eliminated. */ +#define XGCTYPE(a) XTYPE (a) +#endif #ifndef XPNTR #ifdef HAVE_SHM @@ -461,6 +441,9 @@ extern size_t pure_size; #define MOST_NEGATIVE_FIXNUM - ((EMACS_INT) 1 << (VALBITS - 1)) #define MOST_POSITIVE_FIXNUM (((EMACS_INT) 1 << (VALBITS - 1)) - 1) +/* Mask indicating the significant bits of a Lisp_Int. + I.e. (x & INTMASK) == XUINT (make_number (x)). */ +#define INTMASK ((((EMACS_INT) 1) << VALBITS) - 1) /* Value is non-zero if C integer I doesn't fit into a Lisp fixnum. */ @@ -1031,15 +1014,6 @@ struct Lisp_Hash_Table /* These structures are used for various misc types. */ -/* A miscellaneous object, when it's on the free list. */ -struct Lisp_Free - { - int type : 16; /* = Lisp_Misc_Free */ - unsigned gcmarkbit : 1; - int spacer : 15; - union Lisp_Misc *chain; - }; - struct Lisp_Marker { int type : 16; /* = Lisp_Misc_Marker */ @@ -1204,6 +1178,22 @@ struct Lisp_Save_Value }; +/* A miscellaneous object, when it's on the free list. */ +struct Lisp_Free + { + int type : 16; /* = Lisp_Misc_Free */ + unsigned gcmarkbit : 1; + int spacer : 15; + union Lisp_Misc *chain; +#ifdef USE_LSB_TAG + /* Try to make sure that sizeof(Lisp_Misc) preserves TYPEBITS-alignment. + This assumes that Lisp_Marker is the largest of the alternatives and + that Lisp_Intfwd has the same size as "Lisp_Free w/o padding". */ + char padding[((((sizeof (struct Lisp_Marker) - 1) >> GCTYPEBITS) + 1) + << GCTYPEBITS) - sizeof (struct Lisp_Intfwd)]; +#endif + }; + /* To get the type field of a union Lisp_Misc, use XMISCTYPE. It uses one of these struct subtypes to get the type field. */ @@ -1363,7 +1353,7 @@ typedef unsigned char UCHAR; #define GC_NATNUMP(x) (GC_INTEGERP (x) && XINT (x) >= 0) #define INTEGERP(x) (XTYPE ((x)) == Lisp_Int) -#define GC_INTEGERP(x) (XGCTYPE ((x)) == Lisp_Int) +#define GC_INTEGERP(x) INTEGERP (x) #define SYMBOLP(x) (XTYPE ((x)) == Lisp_Symbol) #define GC_SYMBOLP(x) (XGCTYPE ((x)) == Lisp_Symbol) #define MISCP(x) (XTYPE ((x)) == Lisp_Misc) @@ -1434,9 +1424,11 @@ typedef unsigned char UCHAR; #define FRAMEP(x) PSEUDOVECTORP (x, PVEC_FRAME) #define GC_FRAMEP(x) GC_PSEUDOVECTORP (x, PVEC_FRAME) +/* Test for image (image . spec) */ +#define IMAGEP(x) (CONSP (x) && EQ (XCAR (x), Qimage)) + -#define EQ(x, y) (XFASTINT (x) == XFASTINT (y)) -#define GC_EQ(x, y) (XGCTYPE (x) == XGCTYPE (y) && XPNTR (x) == XPNTR (y)) +#define GC_EQ(x, y) EQ (x, y) #define CHECK_LIST(x) \ do { if (!CONSP ((x)) && !NILP (x)) x = wrong_type_argument (Qlistp, (x)); } while (0) @@ -1581,7 +1573,7 @@ typedef unsigned char UCHAR; #define DEFUN(lname, fnname, sname, minargs, maxargs, prompt, doc) \ Lisp_Object fnname (); \ - struct Lisp_Subr sname = \ + DECL_ALIGN (struct Lisp_Subr, sname) = \ { PVEC_SUBR | (sizeof (struct Lisp_Subr) / sizeof (EMACS_INT)), \ fnname, minargs, maxargs, lname, prompt, 0}; \ Lisp_Object fnname @@ -1592,7 +1584,7 @@ typedef unsigned char UCHAR; arguments, so we can catch errors with maxargs at compile-time. */ #define DEFUN(lname, fnname, sname, minargs, maxargs, prompt, doc) \ Lisp_Object fnname DEFUN_ARGS_ ## maxargs ; \ - struct Lisp_Subr sname = \ + DECL_ALIGN (struct Lisp_Subr, sname) = \ { PVEC_SUBR | (sizeof (struct Lisp_Subr) / sizeof (EMACS_INT)), \ fnname, minargs, maxargs, lname, prompt, 0}; \ Lisp_Object fnname @@ -1739,6 +1731,22 @@ extern char *stack_bottom; This is a good thing to do around a loop that has no side effects and (in particular) cannot call arbitrary Lisp code. */ +#ifdef SYNC_INPUT +extern void handle_async_input P_ ((void)); +extern int interrupt_input_pending; +#define QUIT \ + do { \ + if (!NILP (Vquit_flag) && NILP (Vinhibit_quit)) \ + { \ + Vquit_flag = Qnil; \ + Fsignal (Qquit, Qnil); \ + } \ + else if (interrupt_input_pending) \ + handle_async_input (); \ + } while (0) + +#else /* not SYNC_INPUT */ + #define QUIT \ do { \ if (!NILP (Vquit_flag) && NILP (Vinhibit_quit)) \ @@ -1748,6 +1756,9 @@ extern char *stack_bottom; } \ } while (0) +#endif /* not SYNC_INPUT */ + + /* Nonzero if ought to quit now. */ #define QUITP (!NILP (Vquit_flag) && NILP (Vinhibit_quit)) @@ -2019,28 +2030,32 @@ extern Lisp_Object Qerror, Qquit, Qwrong_type_argument, Qargs_out_of_range; extern Lisp_Object Qvoid_variable, Qvoid_function; extern Lisp_Object Qsetting_constant, Qinvalid_read_syntax; extern Lisp_Object Qinvalid_function, Qwrong_number_of_arguments, Qno_catch; -extern Lisp_Object Qend_of_file, Qarith_error; +extern Lisp_Object Qend_of_file, Qarith_error, Qmark_inactive; extern Lisp_Object Qbeginning_of_buffer, Qend_of_buffer, Qbuffer_read_only; -extern Lisp_Object Qmark_inactive, Qtext_read_only; - -extern Lisp_Object Qrange_error, Qdomain_error, Qsingularity_error; -extern Lisp_Object Qoverflow_error, Qunderflow_error; +extern Lisp_Object Qtext_read_only; -extern Lisp_Object Qintegerp, Qnumberp, Qnatnump, Qwholenump; -extern Lisp_Object Qsymbolp, Qlistp, Qconsp; +extern Lisp_Object Qintegerp, Qnatnump, Qwholenump, Qsymbolp, Qlistp, Qconsp; extern Lisp_Object Qstringp, Qarrayp, Qsequencep, Qbufferp; -extern Lisp_Object Qchar_or_string_p, Qmarkerp, Qvectorp; -extern Lisp_Object Qinteger_or_marker_p, Qnumber_or_marker_p; -extern Lisp_Object Qchar_table_p, Qvector_or_char_table_p; -extern Lisp_Object Qboundp, Qfboundp; +extern Lisp_Object Qchar_or_string_p, Qmarkerp, Qinteger_or_marker_p, Qvectorp; extern Lisp_Object Qbuffer_or_string_p; +extern Lisp_Object Qboundp, Qfboundp; +extern Lisp_Object Qchar_table_p, Qvector_or_char_table_p; + extern Lisp_Object Qcdr; -extern Lisp_Object Qfloatp, Qinteger_or_floatp, Qinteger_or_float_or_marker_p; +extern Lisp_Object Qrange_error, Qdomain_error, Qsingularity_error; +extern Lisp_Object Qoverflow_error, Qunderflow_error; -extern Lisp_Object Qframep; +extern Lisp_Object Qfloatp; +extern Lisp_Object Qnumberp, Qnumber_or_marker_p; + +extern Lisp_Object Qinteger; extern void circular_list_error P_ ((Lisp_Object)); +EXFUN (Finteractive_form, 1); + +/* Defined in frame.c */ +extern Lisp_Object Qframep; EXFUN (Feq, 2); EXFUN (Fnull, 1); @@ -2293,6 +2308,15 @@ EXFUN (Ftruncate, 2); extern void init_floatfns P_ ((void)); extern void syms_of_floatfns P_ ((void)); +/* Defined in fringe.c */ +extern void syms_of_fringe P_ ((void)); +extern void init_fringe P_ ((void)); +extern void init_fringe_once P_ ((void)); + +/* Defined in image.c */ +extern void syms_of_image P_ ((void)); +extern void init_image P_ ((void)); + /* Defined in insdel.c */ extern Lisp_Object Qinhibit_modification_hooks; extern void move_gap P_ ((int)); @@ -2347,6 +2371,7 @@ extern Lisp_Object Qinhibit_point_motion_hooks; extern Lisp_Object Qinhibit_redisplay, Qdisplay; extern Lisp_Object Qinhibit_eval_during_redisplay; extern Lisp_Object Qmessage_truncate_lines; +extern Lisp_Object Qimage; extern Lisp_Object Vmessage_log_max; extern int message_enable_multibyte; extern Lisp_Object echo_area_buffer[2]; @@ -2377,7 +2402,6 @@ extern void redisplay P_ ((void)); extern int check_point_in_composition P_ ((struct buffer *, int, struct buffer *, int)); extern void redisplay_preserve_echo_area P_ ((int)); -extern void mark_window_display_accurate P_ ((Lisp_Object, int)); extern void prepare_menu_bars P_ ((void)); void set_frame_cursor_types P_ ((struct frame *, Lisp_Object)); @@ -2673,7 +2697,7 @@ EXFUN (Foverlay_start, 1); EXFUN (Foverlay_end, 1); extern void adjust_overlays_for_insert P_ ((EMACS_INT, EMACS_INT)); extern void adjust_overlays_for_delete P_ ((EMACS_INT, EMACS_INT)); -extern void fix_overlays_in_range P_ ((int, int)); +extern void fix_start_end_in_overlays P_ ((int, int)); extern void report_overlay_modification P_ ((Lisp_Object, Lisp_Object, int, Lisp_Object, Lisp_Object, Lisp_Object)); extern int overlay_touches_p P_ ((int)); @@ -3019,7 +3043,6 @@ extern Lisp_Object next_single_char_property_change P_ ((Lisp_Object, EXFUN (Fx_popup_menu, 2); EXFUN (Fx_popup_dialog, 2); extern void syms_of_xmenu P_ ((void)); -extern int popup_activated_flag; /* defined in sysdep.c */ extern void stuff_char P_ ((char c)); @@ -3069,7 +3092,7 @@ extern void syms_of_category P_ ((void)); extern void syms_of_ccl P_ ((void)); /* Defined in dired.c */ -EXFUN (Ffile_attributes, 1); +EXFUN (Ffile_attributes, 2); extern void syms_of_dired P_ ((void)); /* Defined in term.c */ @@ -3092,7 +3115,6 @@ extern int getloadavg P_ ((double *, int)); #ifdef HAVE_X_WINDOWS /* Defined in xfns.c */ extern void syms_of_xfns P_ ((void)); -extern void init_xfns P_ ((void)); extern Lisp_Object Vx_resource_name; extern Lisp_Object Vx_resource_class; EXFUN (Fxw_display_color_p, 1); @@ -3205,3 +3227,8 @@ extern Lisp_Object Vdirectory_sep_char; (FIXNUM_OVERFLOW_P (val) \ ? make_float (val) \ : make_number ((EMACS_INT)(val))) + +#endif /* EMACS_LISP_H */ + +/* arch-tag: 9b2ed020-70eb-47ac-94ee-e1c2a5107d5e + (do not change this comment) */ diff --git a/src/lread.c b/src/lread.c index 256df2776a5..dd6e3f322a6 100644 --- a/src/lread.c +++ b/src/lread.c @@ -1,5 +1,5 @@ /* Lisp parsing and input streams. - Copyright (C) 1985, 86, 87, 88, 89, 93, 94, 95, 97, 98, 99, 2000, 01, 2003 + Copyright (C) 1985,86,87,88,89,93,94,95,97,98,99,2000,01,03,2004 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -3633,7 +3633,6 @@ defvar_per_buffer (namestring, address, type, doc) { Lisp_Object sym, val; int offset; - extern struct buffer buffer_local_symbols; sym = intern (namestring); val = allocate_misc (); @@ -4114,3 +4113,6 @@ to load. See also `load-dangerous-libraries'. */); Vloads_in_progress = Qnil; staticpro (&Vloads_in_progress); } + +/* arch-tag: a0d02733-0f96-4844-a659-9fd53c4f414d + (do not change this comment) */ diff --git a/src/m/7300.h b/src/m/7300.h index 3db16e67fb6..17dde0c9180 100644 --- a/src/m/7300.h +++ b/src/m/7300.h @@ -92,3 +92,6 @@ Boston, MA 02111-1307, USA. */ /* Insist on using cc when compiling this. GCC may have been configured to use GAS syntax, which causes problems. */ #define CRT0_COMPILE cc -c -O -Demacs + +/* arch-tag: 66219dc7-ef45-4f0c-bb98-f35421f39c8d + (do not change this comment) */ diff --git a/src/m/acorn.h b/src/m/acorn.h index 38b148b3d2e..6f0a77be44c 100644 --- a/src/m/acorn.h +++ b/src/m/acorn.h @@ -179,3 +179,6 @@ do this yet #endif + +/* arch-tag: acee2955-8c49-4b40-813c-579f76f4c0c3 + (do not change this comment) */ diff --git a/src/m/alliant-2800.h b/src/m/alliant-2800.h index dabad592c39..213af43266b 100644 --- a/src/m/alliant-2800.h +++ b/src/m/alliant-2800.h @@ -124,3 +124,6 @@ unexec_text_start = hdr.a_text_addr;} /* Use the K&R version of the DEFUN macro. */ #define USE_NONANSI_DEFUN + +/* arch-tag: 8ba70b15-d082-40f6-931d-14adfd7f9dbd + (do not change this comment) */ diff --git a/src/m/alliant.h b/src/m/alliant.h index 3b79a3c1709..c9c1c70cc95 100644 --- a/src/m/alliant.h +++ b/src/m/alliant.h @@ -117,3 +117,6 @@ unexec_text_start = hdr.a_text_addr;} a variable name causes errors when compiling under ANSI C. */ #define vector xxvector + +/* arch-tag: 0ad5f932-f29a-4458-a24c-496cafdfd50d + (do not change this comment) */ diff --git a/src/m/alliant1.h b/src/m/alliant1.h index 2e061227b47..ca597ac2762 100644 --- a/src/m/alliant1.h +++ b/src/m/alliant1.h @@ -7,3 +7,6 @@ #define ALLIANT_1 #include "alliant.h" + +/* arch-tag: 516688f9-4b94-4356-9bf0-92b2d72e664e + (do not change this comment) */ diff --git a/src/m/alliant4.h b/src/m/alliant4.h index 7e24c53eb89..2ab0a6bde1d 100644 --- a/src/m/alliant4.h +++ b/src/m/alliant4.h @@ -22,3 +22,6 @@ /* include <sys/param.h> for the definition of LOADAVG_SCALE, and also LOADAVG_SIZE, the number of items in the Loadavg array. */ + +/* arch-tag: cf917b55-c95e-4079-a4d1-d31e00c61b66 + (do not change this comment) */ diff --git a/src/m/alpha.h b/src/m/alpha.h index b37116b0d48..3e1d378b292 100644 --- a/src/m/alpha.h +++ b/src/m/alpha.h @@ -149,3 +149,6 @@ NOTE-END Define DBL_MIN_REPLACEMENT to be the next value larger than DBL_MIN: this avoids the assembler bug. */ #define DBL_MIN_REPLACEMENT 2.2250738585072019e-308 + +/* arch-tag: 978cb578-1e25-4a60-819b-adae0972aa78 + (do not change this comment) */ diff --git a/src/m/altos.h b/src/m/altos.h index 654acc1d5c1..b71d006f241 100644 --- a/src/m/altos.h +++ b/src/m/altos.h @@ -53,3 +53,6 @@ Boston, MA 02111-1307, USA. */ #ifdef __GNUC__ #define COFF_ENCAPSULATE #endif + +/* arch-tag: 4572d0ff-70bb-445f-80f1-2bbac3cf47cb + (do not change this comment) */ diff --git a/src/m/amdahl.h b/src/m/amdahl.h index 4e64d0dca85..37cb8c0d362 100644 --- a/src/m/amdahl.h +++ b/src/m/amdahl.h @@ -134,3 +134,6 @@ extern int sign_extend_temp; /* Compensate for error in signal.h. */ #define NSIG_MINIMUM 20 + +/* arch-tag: cf665976-ddb1-49b0-b383-371e17f36acf + (do not change this comment) */ diff --git a/src/m/amdx86-64.h b/src/m/amdx86-64.h index 8043ca0178b..0192afc9d45 100644 --- a/src/m/amdx86-64.h +++ b/src/m/amdx86-64.h @@ -97,20 +97,14 @@ Boston, MA 02111-1307, USA. */ #define PNTR_COMPARISON_TYPE unsigned long -/* On the 64 bit architecture, we can use 60 bits for addresses */ - -#define VALBITS 60 - -/* Define XINT and XUINT so that they can take arguments of type int */ -#define XINT(a) (((long) (a) << (BITS_PER_LONG - VALBITS)) >> (BITS_PER_LONG - VALBITS)) -#define XUINT(a) ((long) (a) & VALMASK) - /* Define XPNTR to avoid or'ing with DATA_SEG_BITS */ - -#define XPNTR(a) XUINT (a) +#undef DATA_SEG_BITS #undef START_FILES #define START_FILES pre-crt0.o /usr/lib64/crt1.o /usr/lib64/crti.o #undef LIB_STANDARD #define LIB_STANDARD -lgcc -lc -lgcc /usr/lib64/crtn.o + +/* arch-tag: 8a5e001d-e12e-4692-a3a6-0b15ba271c6e + (do not change this comment) */ diff --git a/src/m/apollo.h b/src/m/apollo.h index 83af7496e01..e28ffef3379 100644 --- a/src/m/apollo.h +++ b/src/m/apollo.h @@ -90,3 +90,6 @@ Boston, MA 02111-1307, USA. */ /* In SR10.4, unistd.h has bad prototype for getpgrp, so we don't include it. */ #undef HAVE_UNISTD_H + +/* arch-tag: 33336588-6242-4e2e-a194-e38848b12813 + (do not change this comment) */ diff --git a/src/m/arm.h b/src/m/arm.h index 4dafe6819fa..d3a95521e79 100644 --- a/src/m/arm.h +++ b/src/m/arm.h @@ -48,3 +48,6 @@ Boston, MA 02111-1307, USA. */ #define NO_UNION_TYPE #define NO_REMAP + +/* arch-tag: 07856f0c-f0c8-4bd8-99af-0b7fa1e5ee42 + (do not change this comment) */ diff --git a/src/m/att3b.h b/src/m/att3b.h index 46b101dfa4c..559ac2f3c6c 100644 --- a/src/m/att3b.h +++ b/src/m/att3b.h @@ -144,3 +144,6 @@ extern int sign_extend_temp; /* This affects filemode.c. */ #define NO_MODE_T + +/* arch-tag: 07441a37-d630-447f-94fa-7da19645c97a + (do not change this comment) */ diff --git a/src/m/aviion-intel.h b/src/m/aviion-intel.h index 1f422ac0716..eb93a43214f 100644 --- a/src/m/aviion-intel.h +++ b/src/m/aviion-intel.h @@ -17,3 +17,6 @@ #endif #undef m88k /* It sure is NOT a Motorola machine */ + +/* arch-tag: 7cbf89ef-237c-4da5-bdd0-8d569ae5f3ce + (do not change this comment) */ diff --git a/src/m/aviion.h b/src/m/aviion.h index c86eb85d02c..7705ef645fb 100644 --- a/src/m/aviion.h +++ b/src/m/aviion.h @@ -121,3 +121,5 @@ Boston, MA 02111-1307, USA. */ #define SECTION_ALIGNMENT 0x7 +/* arch-tag: 9de8e6ed-ddd8-4480-8308-17ddd7c86559 + (do not change this comment) */ diff --git a/src/m/celerity.h b/src/m/celerity.h index c38d144d9b4..55beedb7c41 100644 --- a/src/m/celerity.h +++ b/src/m/celerity.h @@ -54,3 +54,6 @@ Boston, MA 02111-1307, USA. */ /* (short) negative-int doesn't sign-extend correctly */ #define SHORT_CAST_BUG + +/* arch-tag: b4df1828-fab6-48f8-97bc-b8998c200eea + (do not change this comment) */ diff --git a/src/m/clipper.h b/src/m/clipper.h index 8391d7237ef..dc4dd0c2df8 100644 --- a/src/m/clipper.h +++ b/src/m/clipper.h @@ -92,3 +92,6 @@ Boston, MA 02111-1307, USA. */ #endif /* USG */ #define LD_TEXT_START_ADDR 8000 + +/* arch-tag: 2f7981c1-7018-4a1e-b7b6-b2900de36a04 + (do not change this comment) */ diff --git a/src/m/cnvrgnt.h b/src/m/cnvrgnt.h index 5f76da4bb22..d44eff6700c 100644 --- a/src/m/cnvrgnt.h +++ b/src/m/cnvrgnt.h @@ -91,3 +91,6 @@ Boston, MA 02111-1307, USA. */ Cause crt0.c to define errno. */ #define NEED_ERRNO + +/* arch-tag: 1a227f79-37e4-43af-a186-53c61296b0be + (do not change this comment) */ diff --git a/src/m/convex.h b/src/m/convex.h index 29797fc1314..a871d4ac214 100644 --- a/src/m/convex.h +++ b/src/m/convex.h @@ -183,3 +183,6 @@ Boston, MA 02111-1307, USA. */ /* There is some indication that the convex has sys/wait.h but it does not work right. */ #undef HAVE_SYS_WAIT_H + +/* arch-tag: 127e5ae1-4f03-40c0-a87e-d2cb02c59de8 + (do not change this comment) */ diff --git a/src/m/cydra5.h b/src/m/cydra5.h index 7f227e36df9..12b757305ba 100644 --- a/src/m/cydra5.h +++ b/src/m/cydra5.h @@ -111,3 +111,6 @@ Boston, MA 02111-1307, USA. */ /* We can't do interrupt-driven input, so don't let user try. */ #define BROKEN_SIGIO + +/* arch-tag: ad70aae4-1f54-4e67-8677-6eeafb9bcbd9 + (do not change this comment) */ diff --git a/src/m/delta88k.h b/src/m/delta88k.h index 0b574ef0ca4..89889824fd1 100644 --- a/src/m/delta88k.h +++ b/src/m/delta88k.h @@ -157,3 +157,6 @@ Boston, MA 02111-1307, USA. */ #define NO_PTY_H #define USE_GETOBAUD + +/* arch-tag: c8ea1965-99d7-43df-ba32-29b66fc069be + (do not change this comment) */ diff --git a/src/m/dpx2.h b/src/m/dpx2.h index 282c4bd877e..1a2b99cdffc 100644 --- a/src/m/dpx2.h +++ b/src/m/dpx2.h @@ -217,3 +217,5 @@ Boston, MA 02111-1307, USA. */ /* end of dpx2.h */ +/* arch-tag: 8cfdf817-aec7-4d99-a00d-0e77615e8e1b + (do not change this comment) */ diff --git a/src/m/dual.h b/src/m/dual.h index d00a30d9345..392cb64eb49 100644 --- a/src/m/dual.h +++ b/src/m/dual.h @@ -67,3 +67,6 @@ NOTE-END */ /* Change some things to avoid bugs in compiler */ #define SWITCH_ENUM_BUG 1 + +/* arch-tag: 7208d63c-9a23-469e-a9b1-908ac912c743 + (do not change this comment) */ diff --git a/src/m/elxsi.h b/src/m/elxsi.h index b392e07c5f0..1795d9815d3 100644 --- a/src/m/elxsi.h +++ b/src/m/elxsi.h @@ -127,3 +127,6 @@ Boston, MA 02111-1307, USA. */ extern int _init_brk;\ _init_brk = bss_start;\ } + +/* arch-tag: 73bf1120-a994-4c29-8d60-af425d8bf10c + (do not change this comment) */ diff --git a/src/m/ews4800.h b/src/m/ews4800.h index 5f5f9cae000..b782542348c 100644 --- a/src/m/ews4800.h +++ b/src/m/ews4800.h @@ -36,3 +36,6 @@ Boston, MA 02111-1307, USA. */ #undef C_DEBUG_SWITCH #define C_DEBUG_SWITCH -O -KOlimit=3000 -ZXNd=5000 #endif /* !__GNUC__ */ + +/* arch-tag: 27f72f54-45cd-40a3-b182-345127f04955 + (do not change this comment) */ diff --git a/src/m/f301.h b/src/m/f301.h index 1ec0b221386..c427c19e05d 100644 --- a/src/m/f301.h +++ b/src/m/f301.h @@ -5,3 +5,6 @@ USUAL-OPSYS="uxpv" */ #include "delta88k.h" + +/* arch-tag: a0ed4f18-ecf2-4d9a-853b-36e0f6b45945 + (do not change this comment) */ diff --git a/src/m/gould-np1.h b/src/m/gould-np1.h index fcbeac3b6ca..145d682afb1 100644 --- a/src/m/gould-np1.h +++ b/src/m/gould-np1.h @@ -103,3 +103,5 @@ Boston, MA 02111-1307, USA. */ #endif +/* arch-tag: cdfd3dbf-a5e4-464d-8cef-985fb7872873 + (do not change this comment) */ diff --git a/src/m/gould.h b/src/m/gould.h index af77843a9f2..eeac2aef2f6 100644 --- a/src/m/gould.h +++ b/src/m/gould.h @@ -183,3 +183,6 @@ NOTE-END */ with `environ' the way most standard crt0.o's do. */ #define START_FILES pre-crt0.o /lib/crt0.o + +/* arch-tag: 930cb9ef-f56f-4c06-aea0-5e81103bbf58 + (do not change this comment) */ diff --git a/src/m/hp800.h b/src/m/hp800.h index bc51b31836a..8f08ed3b617 100644 --- a/src/m/hp800.h +++ b/src/m/hp800.h @@ -67,12 +67,6 @@ Boston, MA 02111-1307, USA. */ #define XSET(var, type, ptr) \ ((var) = ((int)(type) << VALBITS) + (((unsigned) (ptr) << BITS_PER_INT-VALBITS) >> BITS_PER_INT-VALBITS)) - -#define XMARKBIT(a) ((a) < 0) - -#if 0 /* Loses when sign bit of type field is set. */ -#define XUNMARK(a) ((a) = (((a) << BITS_PER_INT-GCTYPEBITS-VALBITS) >> BITS_PER_INT-GCTYPEBITS-VALBITS)) -#endif /* Common definitions for HPUX and GNU/Linux. */ @@ -179,3 +173,6 @@ Boston, MA 02111-1307, USA. */ #define rindex strrchr #endif /* __hpux */ + +/* arch-tag: 809436e6-1645-4b92-b40d-2de5d6e7227c + (do not change this comment) */ diff --git a/src/m/hp9000s300.h b/src/m/hp9000s300.h index ad4ca111664..24c9a521d0c 100644 --- a/src/m/hp9000s300.h +++ b/src/m/hp9000s300.h @@ -222,3 +222,6 @@ NOTE-END */ #endif #endif /* not BSD4_3 */ + +/* arch-tag: 6e0001a5-ed62-4258-9235-204348f6bdb9 + (do not change this comment) */ diff --git a/src/m/i860.h b/src/m/i860.h index 48222538380..9d56b886f62 100644 --- a/src/m/i860.h +++ b/src/m/i860.h @@ -95,3 +95,6 @@ Boston, MA 02111-1307, USA. */ #define SVR4 #endif #endif + +/* arch-tag: 99f3a078-95e1-49d6-8666-04726eb25647 + (do not change this comment) */ diff --git a/src/m/ia64.h b/src/m/ia64.h index a765fab1543..7114382d513 100644 --- a/src/m/ia64.h +++ b/src/m/ia64.h @@ -119,15 +119,6 @@ Boston, MA 02111-1307, USA. */ #define PNTR_COMPARISON_TYPE unsigned long -/* On the 64 bit architecture, we can use 60 bits for addresses */ - -#define VALBITS 60 - -/* Define XINT and XUINT so that they can take arguments of type int */ - -#define XINT(a) (((long) (a) << (BITS_PER_LONG - VALBITS)) >> (BITS_PER_LONG - VALBITS)) -#define XUINT(a) ((long) (a) & VALMASK) - #ifndef NOT_C_CODE #ifdef REL_ALLOC @@ -145,3 +136,6 @@ extern void r_alloc_free (); #define DATA_SEG_BITS 0x6000000000000000 #define HAVE_TEXT_START + +/* arch-tag: 9b8e9fb2-2e49-4c22-b68f-11a488e77c66 + (do not change this comment) */ diff --git a/src/m/ibm370aix.h b/src/m/ibm370aix.h index 32dc30089a5..3fb228afa18 100644 --- a/src/m/ibm370aix.h +++ b/src/m/ibm370aix.h @@ -53,3 +53,6 @@ Boston, MA 02111-1307, USA. */ #undef LD_SWITCH_MACHINE #define LD_SWITCH_MACHINE -xa + +/* arch-tag: 8605b600-0580-4e49-9ba9-8b4a977f860a + (do not change this comment) */ diff --git a/src/m/ibmps2-aix.h b/src/m/ibmps2-aix.h index a29d916451d..eb843ffe71b 100644 --- a/src/m/ibmps2-aix.h +++ b/src/m/ibmps2-aix.h @@ -230,3 +230,6 @@ so disable it for them. */ #define LD_SWITCH_MACHINE -shlib #endif #endif + +/* arch-tag: 2e7f44df-6a61-4a47-aa53-f7961bfeff11 + (do not change this comment) */ diff --git a/src/m/ibmrs6000.h b/src/m/ibmrs6000.h index 650530bf4c0..5be14b04884 100644 --- a/src/m/ibmrs6000.h +++ b/src/m/ibmrs6000.h @@ -182,3 +182,6 @@ Boston, MA 02111-1307, USA. */ #define NLIST_STRUCT #endif #endif /* USG5_4 */ + +/* arch-tag: 028318ee-a7ae-4a08-804d-cc1e6588d003 + (do not change this comment) */ diff --git a/src/m/ibmrs6000.inp b/src/m/ibmrs6000.inp index d28a3aedae1..d7f3fddaf6f 100644 --- a/src/m/ibmrs6000.inp +++ b/src/m/ibmrs6000.inp @@ -1,2 +1,4 @@ #! pthread_yield + +# arch-tag: fc6d01ea-c488-4862-bbdb-e8d3e0f6fdb3 diff --git a/src/m/ibmrt-aix.h b/src/m/ibmrt-aix.h index 26803238953..8bce9fb6f69 100644 --- a/src/m/ibmrt-aix.h +++ b/src/m/ibmrt-aix.h @@ -159,3 +159,6 @@ Boston, MA 02111-1307, USA. */ /* rocky@watson.ibm.com says this is needed. */ #define HAVE_FTIME + +/* arch-tag: eea85307-0ca9-4a9c-a4f6-89fad7591d28 + (do not change this comment) */ diff --git a/src/m/ibmrt.h b/src/m/ibmrt.h index 587729e1418..9c262640570 100644 --- a/src/m/ibmrt.h +++ b/src/m/ibmrt.h @@ -117,3 +117,6 @@ Boston, MA 02111-1307, USA. */ /* Use the bitmap files that come with Emacs. */ #define EMACS_BITMAP_FILES + +/* arch-tag: 89aa7e7d-593e-432c-966a-3db6aa2ad665 + (do not change this comment) */ diff --git a/src/m/ibms390.h b/src/m/ibms390.h index 711681267a4..8797a49d307 100644 --- a/src/m/ibms390.h +++ b/src/m/ibms390.h @@ -111,3 +111,6 @@ Boston, MA 02111-1307, USA. */ If you've just fixed a problem in an existing configuration file, you should also check `etc/MACHINES' to make sure its descriptions of known problems in that configuration should be updated. */ + +/* arch-tag: d8a0ffa4-a8f0-4736-90d3-7fd7b21b8314 + (do not change this comment) */ diff --git a/src/m/intel386.h b/src/m/intel386.h index 7f9f616d25a..e240beb91a3 100644 --- a/src/m/intel386.h +++ b/src/m/intel386.h @@ -212,3 +212,6 @@ NOTE-END */ #define SEGMENT_MASK ((SEGMENT_SIZE)-1) #endif + +/* arch-tag: 746338f0-cb7b-4f49-a98c-cb50817cf2ec + (do not change this comment) */ diff --git a/src/m/iris4d.h b/src/m/iris4d.h index 457f3594636..8d3b7a883bd 100644 --- a/src/m/iris4d.h +++ b/src/m/iris4d.h @@ -1,5 +1,5 @@ /* machine description file for Iris-4D machines. Use with s/irix*.h. - Copyright (C) 1987, 2002 Free Software Foundation, Inc. + Copyright (C) 1987, 2002, 2003 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -159,7 +159,10 @@ Boston, MA 02111-1307, USA. */ #undef FIRST_PTY_LETTER #define FIRST_PTY_LETTER 'q' -#ifndef _LP64 +#if _MIPS_SZLONG != 64 +/* fixme: should there be 64-bit defiitions? (The ones below aren't + OK.) */ + /* The standard definitions of these macros would work ok, but these are faster because the constants are short. */ @@ -167,8 +170,6 @@ Boston, MA 02111-1307, USA. */ #define XSET(var, type, ptr) \ ((var) = ((int)(type) << VALBITS) + (((unsigned) (ptr) << BITS_PER_INT-VALBITS) >> BITS_PER_INT-VALBITS)) - -#define XUNMARK(a) ((a) = (((unsigned)(a) << BITS_PER_INT-GCTYPEBITS-VALBITS) >> BITS_PER_INT-GCTYPEBITS-VALBITS)) #endif /* _LP64 */ #ifndef __GNUC__ @@ -185,3 +186,6 @@ Boston, MA 02111-1307, USA. */ #endif #endif /* not __GNUC__ */ + +/* arch-tag: fff5e139-9ae0-465d-afec-837c41ea0aa6 + (do not change this comment) */ diff --git a/src/m/irist.h b/src/m/irist.h index b365371324f..d2b9dd28314 100644 --- a/src/m/irist.h +++ b/src/m/irist.h @@ -130,3 +130,6 @@ NOTE-END */ #define internal_with_output_to_temp_buffer stupid_long_name1 #define Finsert_abbrev_table_description stupid_long_name2 + +/* arch-tag: 4076b26c-1fe6-4c28-94f3-3c863f074767 + (do not change this comment) */ diff --git a/src/m/is386.h b/src/m/is386.h index 0c89fdf91c6..02fe12d93e5 100644 --- a/src/m/is386.h +++ b/src/m/is386.h @@ -25,3 +25,6 @@ NOTE-END */ #define LIBX11_MACHINE -lnsl_s #define LIBS_DEBUG -lg + +/* arch-tag: b6b7e6ec-8b6c-440b-b9c8-961e4bebf0cf + (do not change this comment) */ diff --git a/src/m/isi-ov.h b/src/m/isi-ov.h index a1ab808923a..ef481e13f2b 100644 --- a/src/m/isi-ov.h +++ b/src/m/isi-ov.h @@ -90,3 +90,6 @@ NOTE-END */ #define LIB_STANDARD -lmc -lc #define C_DEBUG_SWITCH -20 -O -X23 #endif + +/* arch-tag: 3bfb5a11-d94e-4372-923b-9f47d0851f42 + (do not change this comment) */ diff --git a/src/m/m68k.h b/src/m/m68k.h index 3391bb17805..ce7b268bbec 100644 --- a/src/m/m68k.h +++ b/src/m/m68k.h @@ -81,3 +81,6 @@ Boston, MA 02111-1307, USA. */ #define NO_REMAP #define TEXT_START 0 #endif + +/* arch-tag: 4eadd161-b4e8-4b82-82a1-e4ce7f42969d + (do not change this comment) */ diff --git a/src/m/macppc.h b/src/m/macppc.h index 6f8f841a46c..21ba90ad101 100644 --- a/src/m/macppc.h +++ b/src/m/macppc.h @@ -104,3 +104,6 @@ Boston, MA 02111-1307, USA. */ #endif #endif #endif /* 0 */ + +/* arch-tag: 41913e4e-e7d1-4023-aadb-210cc31712ed + (do not change this comment) */ diff --git a/src/m/masscomp.h b/src/m/masscomp.h index 0b045794e42..34ea78696c1 100644 --- a/src/m/masscomp.h +++ b/src/m/masscomp.h @@ -116,3 +116,6 @@ Boston, MA 02111-1307, USA. */ #define ADJUST_EXEC_HEADER \ hdr.a_stamp = STAMP13; /* really want the latest stamp, whatever it is */ + +/* arch-tag: 572bf8d1-7a94-48c6-b188-bf69754e0cd2 + (do not change this comment) */ diff --git a/src/m/mega68.h b/src/m/mega68.h index fccd495e0d8..e86a5048680 100644 --- a/src/m/mega68.h +++ b/src/m/mega68.h @@ -47,3 +47,6 @@ Boston, MA 02111-1307, USA. */ /* Convert that into an integer that is 100 for a load average of 1.0 */ #define LOAD_AVE_CVT(x) ((int) ((x) * 100.0)) + +/* arch-tag: 61e6deb4-a93e-444b-bbd5-9887a83f1bbc + (do not change this comment) */ diff --git a/src/m/mg1.h b/src/m/mg1.h index bf6e708bd7e..5a6250c3c31 100644 --- a/src/m/mg1.h +++ b/src/m/mg1.h @@ -101,3 +101,6 @@ NOTE-END */ /* Avoids a compiler bug */ /* borrowed from sequent.h */ + +/* arch-tag: e15d9072-9e1a-44bf-8add-966be535967b + (do not change this comment) */ diff --git a/src/m/mips-siemens.h b/src/m/mips-siemens.h index d0935ce6160..11b1f971d27 100644 --- a/src/m/mips-siemens.h +++ b/src/m/mips-siemens.h @@ -1,5 +1,5 @@ /* m- file for Mips machines. - Copyright (C) 1987, 1992, 1993, 1995, 2002 Free Software Foundation, Inc. + Copyright (C) 1987,1992,1993,95,2002,03 Free Software Foundation, Inc. This file contains some changes for our SVR4 based SINIX-Mips 5.4. I hope this is helpful to port the emacs to our RM?00 series and @@ -158,8 +158,5 @@ NOTE-END */ ((int)(type) << VALBITS) \ + (((unsigned) (ptr) << (BITS_PER_INT-VALBITS)) >> (BITS_PER_INT-VALBITS))) -#define XUNMARK(a) \ - ((a) = \ - (((unsigned)(a) << (BITS_PER_INT-GCTYPEBITS-VALBITS)) \ - >> (BITS_PER_INT-GCTYPEBITS-VALBITS))) - +/* arch-tag: a4f5c090-0bd5-48f0-9724-b7d531f9b6c8 + (do not change this comment) */ diff --git a/src/m/mips.h b/src/m/mips.h index 3948cb6855c..cca45868178 100644 --- a/src/m/mips.h +++ b/src/m/mips.h @@ -1,5 +1,5 @@ /* m- file for Mips machines. - Copyright (C) 1987, 1992, 1999, 2002 Free Software Foundation, Inc. + Copyright (C) 1987, 1992, 1999, 2002, 2003 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -170,11 +170,6 @@ NOTE-END */ ((var) = \ ((int)(type) << VALBITS) \ + (((unsigned) (ptr) << (BITS_PER_INT-VALBITS)) >> (BITS_PER_INT-VALBITS))) - -#define XUNMARK(a) \ - ((a) = \ - (((unsigned)(a) << (BITS_PER_INT-GCTYPEBITS-VALBITS)) \ - >> (BITS_PER_INT-GCTYPEBITS-VALBITS))) #if !defined (NEWSOS5) && !defined (__linux__) #ifdef USG @@ -217,3 +212,6 @@ NOTE-END */ #endif /* BSD_SYSTEM */ #endif /* not NEWSOS5 && not __linux__ */ + +/* arch-tag: 8fd020ee-78a7-4d87-96ce-6129f52f7bee + (do not change this comment) */ diff --git a/src/m/mips4.h b/src/m/mips4.h index 5371fc03200..4b79e466fb3 100644 --- a/src/m/mips4.h +++ b/src/m/mips4.h @@ -57,3 +57,6 @@ NOTE-END */ #undef HAVE_XSCREENRESOURCESTRING #undef HAVE_SETSID #endif + +/* arch-tag: 56050454-0df5-4de9-b1b7-0c6ab400313c + (do not change this comment) */ diff --git a/src/m/ncr386.h b/src/m/ncr386.h index 2599456a873..f98566a2959 100644 --- a/src/m/ncr386.h +++ b/src/m/ncr386.h @@ -13,3 +13,6 @@ #define LD_SWITCH_X_DEFAULT -Xlinker LD_SWITCH_X_SITE_AUX #endif /* __GNUC__ */ + +/* arch-tag: 79c76283-7d50-499b-b910-8ef980357758 + (do not change this comment) */ diff --git a/src/m/news-r6.h b/src/m/news-r6.h index 7018dc9571a..cf6e019fd05 100644 --- a/src/m/news-r6.h +++ b/src/m/news-r6.h @@ -49,7 +49,5 @@ ((int)(type) << VALBITS) \ + (((unsigned) (ptr) << (BITS_PER_INT-VALBITS)) >> (BITS_PER_INT-VALBITS))) -#define XUNMARK(a) \ - ((a) = \ - (((unsigned)(a) << (BITS_PER_INT-GCTYPEBITS-VALBITS)) \ - >> (BITS_PER_INT-GCTYPEBITS-VALBITS))) +/* arch-tag: b9fd7b75-ba3c-46d4-8966-24381b13001b + (do not change this comment) */ diff --git a/src/m/news-risc.h b/src/m/news-risc.h index cba5bbc5689..2ecaff41cb9 100644 --- a/src/m/news-risc.h +++ b/src/m/news-risc.h @@ -57,3 +57,6 @@ #define BROKEN_PROTOTYPES #endif /* not NEWSOS5 */ + +/* arch-tag: cf17300c-dd34-4b9d-a657-2de718469662 + (do not change this comment) */ diff --git a/src/m/news.h b/src/m/news.h index 812432d8f38..1a594ad82a7 100644 --- a/src/m/news.h +++ b/src/m/news.h @@ -60,3 +60,5 @@ NOTE-END */ #define LIBS_TERMCAP -ltermcap +/* arch-tag: 79bfd831-874a-4339-85fa-b8cbdc29bdab + (do not change this comment) */ diff --git a/src/m/next.h b/src/m/next.h index b2ceb49f434..1e8a3d3a31c 100644 --- a/src/m/next.h +++ b/src/m/next.h @@ -121,3 +121,6 @@ Boston, MA 02111-1307, USA. */ /* This should be true for recent NeXT systems. At least since 3.2. */ #define HAVE_MACH_MACH_H + +/* arch-tag: 1155cdcb-1f6c-4208-a2da-22c7473060a1 + (do not change this comment) */ diff --git a/src/m/nh3000.h b/src/m/nh3000.h index 4df55957d90..d6c09bd65b5 100644 --- a/src/m/nh3000.h +++ b/src/m/nh3000.h @@ -103,3 +103,6 @@ Boston, MA 02111-1307, USA. */ */ /* #define NO_SOCK_SIGIO */ + +/* arch-tag: 1529f2bc-50d9-42e7-ae72-6f40afadf09e + (do not change this comment) */ diff --git a/src/m/nh4000.h b/src/m/nh4000.h index d002405fe13..70804ef2c36 100644 --- a/src/m/nh4000.h +++ b/src/m/nh4000.h @@ -102,3 +102,6 @@ Boston, MA 02111-1307, USA. */ */ /* #define NO_SOCK_SIGIO */ + +/* arch-tag: d9e12769-ae79-4c25-953f-70db5b7ef5dd + (do not change this comment) */ diff --git a/src/m/ns16000.h b/src/m/ns16000.h index f684c3dcc6d..549f648c7f8 100644 --- a/src/m/ns16000.h +++ b/src/m/ns16000.h @@ -89,3 +89,6 @@ NOTE-END */ #define static #endif /* USG */ + +/* arch-tag: 4210db3c-e35c-4b96-9399-1dbde3e00a57 + (do not change this comment) */ diff --git a/src/m/ns32000.h b/src/m/ns32000.h index c3183862355..214954b631a 100644 --- a/src/m/ns32000.h +++ b/src/m/ns32000.h @@ -96,3 +96,6 @@ Boston, MA 02111-1307, USA. */ #define START_FILES pre-crt0.o /lib/crt0.o #endif + +/* arch-tag: 13dde0e0-8ed5-4bc3-a0dc-5456c9db5f94 + (do not change this comment) */ diff --git a/src/m/nu.h b/src/m/nu.h index 8eb9374e6da..44abc929053 100644 --- a/src/m/nu.h +++ b/src/m/nu.h @@ -69,3 +69,6 @@ Boston, MA 02111-1307, USA. */ in the executable file. */ #define SECTION_ALIGNMENT pagemask + +/* arch-tag: 7d2d9b6d-75d4-4c0d-96a9-a41f06212f35 + (do not change this comment) */ diff --git a/src/m/orion.h b/src/m/orion.h index 2a89251e23c..76519f6fe68 100644 --- a/src/m/orion.h +++ b/src/m/orion.h @@ -64,3 +64,6 @@ Boston, MA 02111-1307, USA. */ #define FSCALE 1.0 #endif #define LOAD_AVE_CVT(x) (int) (((double) (x)) * 100.0 / FSCALE) + +/* arch-tag: 4fcf38ad-d6b0-434b-bc10-16647d5a7fb6 + (do not change this comment) */ diff --git a/src/m/orion105.h b/src/m/orion105.h index 7e5fb34b319..c58f9222068 100644 --- a/src/m/orion105.h +++ b/src/m/orion105.h @@ -66,3 +66,6 @@ Boston, MA 02111-1307, USA. */ /* Arguments to ignore before argc in crt0.c. */ #define DUMMIES dummy1, dummy2, + +/* arch-tag: 32fed6e3-8cae-4882-b327-a68c2af6db7a + (do not change this comment) */ diff --git a/src/m/paragon.h b/src/m/paragon.h index 5c00f7d8d92..11b98dea7ee 100644 --- a/src/m/paragon.h +++ b/src/m/paragon.h @@ -8,3 +8,6 @@ #define KEEP_OLD_TEXT_SCNPTR #define KEEP_OLD_PADDR #define drem fmod + +/* arch-tag: c1bc280c-25e5-4993-9b91-333c52ab3674 + (do not change this comment) */ diff --git a/src/m/pfa50.h b/src/m/pfa50.h index c417a1d58ad..c6762a93120 100644 --- a/src/m/pfa50.h +++ b/src/m/pfa50.h @@ -87,3 +87,6 @@ Boston, MA 02111-1307, USA. */ #define NO_SIOCTL_H #define BROKEN_SIGIO + +/* arch-tag: f3a127d5-790b-4c78-b6be-837139fb12c4 + (do not change this comment) */ diff --git a/src/m/plexus.h b/src/m/plexus.h index 22dbffa16f9..b7012c750d6 100644 --- a/src/m/plexus.h +++ b/src/m/plexus.h @@ -103,3 +103,6 @@ Boston, MA 02111-1307, USA. */ /* This triggers some stuff to avoid a compiler bug */ #define TAHOE_REGISTER_BUG + +/* arch-tag: 78c607eb-b4f8-4750-b575-39670d979448 + (do not change this comment) */ diff --git a/src/m/pmax.h b/src/m/pmax.h index 54f246fed65..911f84d3c8a 100644 --- a/src/m/pmax.h +++ b/src/m/pmax.h @@ -105,3 +105,6 @@ NOTE-END */ /* Enable a fix in process.c. */ #define SET_CHILD_PTY_PGRP + +/* arch-tag: 45d5070e-d2b7-479f-b336-3fd497c36e15 + (do not change this comment) */ diff --git a/src/m/powermac.h b/src/m/powermac.h index 0ab535dfd23..dc698675eaa 100644 --- a/src/m/powermac.h +++ b/src/m/powermac.h @@ -109,3 +109,6 @@ Boston, MA 02111-1307, USA. */ If you've just fixed a problem in an existing configuration file, you should also check `etc/MACHINES' to make sure its descriptions of known problems in that configuration should be updated. */ + +/* arch-tag: d8af08a6-48b3-4c8a-94a0-0b4acae5e1f0 + (do not change this comment) */ diff --git a/src/m/powerpcle.h b/src/m/powerpcle.h index 2c01acb843d..4733156337a 100644 --- a/src/m/powerpcle.h +++ b/src/m/powerpcle.h @@ -56,3 +56,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Control a conditional in unexelf.c. */ #define SOLARIS_POWERPC + +/* arch-tag: dc2c3cb6-4683-45ae-961f-0a4f2bda3c61 + (do not change this comment) */ diff --git a/src/m/pyramid.h b/src/m/pyramid.h index 7abd4f88b3f..7ba6a9e058e 100644 --- a/src/m/pyramid.h +++ b/src/m/pyramid.h @@ -61,3 +61,6 @@ Boston, MA 02111-1307, USA. */ /* Reenable this #define for old versions of the Pyramid system. */ /* #define PYRAMID_OLD */ + +/* arch-tag: b9097bc9-92be-46d4-acb1-13c2b966d581 + (do not change this comment) */ diff --git a/src/m/pyrmips.h b/src/m/pyrmips.h index 1489ddaa664..67705fb6619 100644 --- a/src/m/pyrmips.h +++ b/src/m/pyrmips.h @@ -6,3 +6,5 @@ #define SYSTEM_MALLOC #define CANNOT_DUMP +/* arch-tag: 82559148-25a8-466d-bbb3-f903f7666b7a + (do not change this comment) */ diff --git a/src/m/sequent-ptx.h b/src/m/sequent-ptx.h index 2c815ff97bb..a72c7055780 100644 --- a/src/m/sequent-ptx.h +++ b/src/m/sequent-ptx.h @@ -127,3 +127,5 @@ Boston, MA 02111-1307, USA. */ /* Use terminfo library. */ #define LIBS_TERMCAP -ltermlib +/* arch-tag: 0494629b-7e11-4f6f-865f-62254ac46099 + (do not change this comment) */ diff --git a/src/m/sequent.h b/src/m/sequent.h index 404bbf54668..7e45c4f4fda 100644 --- a/src/m/sequent.h +++ b/src/m/sequent.h @@ -163,3 +163,6 @@ NOTE-END */ sprintf (ptyname, "/dev/pty%c%c", PTY_MAJOR[ma], PTY_MINOR[mi]); #define PTY_TTY_NAME_SPRINTF \ sprintf (ptyname, "/dev/tty%c%c", PTY_MAJOR[ma], PTY_MINOR[mi]); + +/* arch-tag: 81caea48-aa64-4021-9544-e969dea71ee8 + (do not change this comment) */ diff --git a/src/m/sparc.h b/src/m/sparc.h index 8e22ccb2b21..8656152fb7a 100644 --- a/src/m/sparc.h +++ b/src/m/sparc.h @@ -97,3 +97,6 @@ NOTE-END */ should be here. -- fx */ #endif #endif + +/* arch-tag: 0a6f7882-33fd-4811-9832-7466c51e50f7 + (do not change this comment) */ diff --git a/src/m/sps7.h b/src/m/sps7.h index 1589f2cbfb2..ba4eae18510 100644 --- a/src/m/sps7.h +++ b/src/m/sps7.h @@ -112,3 +112,6 @@ Boston, MA 02111-1307, USA. */ #define ADJUST_EXEC_HEADER f_hdr.f_magic = SMROMAGIC;\ f_ohdr.stsize = 0; #endif + +/* arch-tag: 2240f71c-6f3b-4a82-80fc-4d56c682d7ad + (do not change this comment) */ diff --git a/src/m/sr2k.h b/src/m/sr2k.h index 579432aa3b0..088ea23d94c 100644 --- a/src/m/sr2k.h +++ b/src/m/sr2k.h @@ -67,12 +67,6 @@ Boston, MA 02111-1307, USA. */ #define XSET(var, type, ptr) \ ((var) = ((int)(type) << VALBITS) + (((unsigned) (ptr) << BITS_PER_INT-VALBITS) >> BITS_PER_INT-VALBITS)) - -#define XMARKBIT(a) ((a) < 0) - -#if 0 /* Loses when sign bit of type field is set. */ -#define XUNMARK(a) ((a) = (((a) << BITS_PER_INT-GCTYPEBITS-VALBITS) >> BITS_PER_INT-GCTYPEBITS-VALBITS)) -#endif /* #ifdef __hpux */ /* Now define a symbol for the cpu type, if your compiler @@ -160,3 +154,6 @@ Boston, MA 02111-1307, USA. */ #define rindex strrchr /* #endif */ + +/* arch-tag: 4ced5b51-ffe6-4be1-9954-eb40657023a5 + (do not change this comment) */ diff --git a/src/m/stride.h b/src/m/stride.h index 4e1fd18dc91..941b9d7cc98 100644 --- a/src/m/stride.h +++ b/src/m/stride.h @@ -115,3 +115,6 @@ Boston, MA 02111-1307, USA. */ /* Define this macro if system defines a type `union wait'. */ #define HAVE_UNION_WAIT + +/* arch-tag: 65c635ed-5bc7-4ace-ab20-f3442429c8ba + (do not change this comment) */ diff --git a/src/m/sun1.h b/src/m/sun1.h index 6bff1d21677..54d51106e6b 100644 --- a/src/m/sun1.h +++ b/src/m/sun1.h @@ -74,3 +74,6 @@ NOTE-END */ /* Mask for address bits within a memory segment */ #define SEGMENT_MASK (SEGSIZ - 1) + +/* arch-tag: 58ec9c79-48bd-4d1b-aad1-65a09a6b0d10 + (do not change this comment) */ diff --git a/src/m/sun2.h b/src/m/sun2.h index 5107f3c47d2..33f811aea04 100644 --- a/src/m/sun2.h +++ b/src/m/sun2.h @@ -95,3 +95,6 @@ NOTE-END */ #define SYMS_MACHINE syms_of_sunfns () #define PURESIZE 132000 #endif + +/* arch-tag: 543c3570-74ca-4099-aa47-db7c7b691c8e + (do not change this comment) */ diff --git a/src/m/sun3-68881.h b/src/m/sun3-68881.h index 1210bef6300..33b9c2bd527 100644 --- a/src/m/sun3-68881.h +++ b/src/m/sun3-68881.h @@ -26,3 +26,6 @@ NOTE-END */ #define sun_68881 #define START_FILES crt0.o /usr/lib/Mcrt1.o + +/* arch-tag: f8659e89-5f5e-4921-940c-814a5786b901 + (do not change this comment) */ diff --git a/src/m/sun3-fpa.h b/src/m/sun3-fpa.h index 1b2c084e010..b78adaf7378 100644 --- a/src/m/sun3-fpa.h +++ b/src/m/sun3-fpa.h @@ -26,3 +26,6 @@ NOTE-END */ #define sun_fpa #define START_FILES crt0.o /usr/lib/Wcrt1.o + +/* arch-tag: db287fbb-966f-4a70-a3f4-a6768c09326b + (do not change this comment) */ diff --git a/src/m/sun3-soft.h b/src/m/sun3-soft.h index 0913e875d8a..32b2558c01b 100644 --- a/src/m/sun3-soft.h +++ b/src/m/sun3-soft.h @@ -27,3 +27,6 @@ NOTE-END */ #define sun_soft #define START_FILES crt0.o /usr/lib/Fcrt1.o + +/* arch-tag: 76e9d7e6-66a8-4c4f-b0a5-335d082e5720 + (do not change this comment) */ diff --git a/src/m/sun3.h b/src/m/sun3.h index 24f84d8e2da..b2713703416 100644 --- a/src/m/sun3.h +++ b/src/m/sun3.h @@ -48,3 +48,6 @@ NOTE-END */ For maximum cleanliness, don't edit this file; instead, insert this line in config.h. */ /* #define START_FILES crt0.o /usr/lib/Mcrt1.o */ + +/* arch-tag: d0559a79-2285-4a78-ad68-9694264d0d8a + (do not change this comment) */ diff --git a/src/m/sun386.h b/src/m/sun386.h index 61468f99879..d3866e8f177 100644 --- a/src/m/sun386.h +++ b/src/m/sun386.h @@ -80,3 +80,6 @@ NOTE-END */ on the 386 needs this. */ #define LIBS_MACHINE -lkvm #endif + +/* arch-tag: 861af4b4-ce5f-475e-876e-ebff6436a1fe + (do not change this comment) */ diff --git a/src/m/symmetry.h b/src/m/symmetry.h index a3e89c58490..ca584c9c6e1 100644 --- a/src/m/symmetry.h +++ b/src/m/symmetry.h @@ -89,3 +89,6 @@ Boston, MA 02111-1307, USA. */ sprintf (pty_name, "/dev/pty%c%c", PTY_MAJOR[ma], PTY_MINOR[mi]); #define PTY_TTY_NAME_SPRINTF \ sprintf (pty_name, "/dev/tty%c%c", PTY_MAJOR[ma], PTY_MINOR[mi]); + +/* arch-tag: 4169a89e-3764-4147-98df-1ba3bdd45a5b + (do not change this comment) */ diff --git a/src/m/tad68k.h b/src/m/tad68k.h index 4aa142fbd91..084e432223e 100644 --- a/src/m/tad68k.h +++ b/src/m/tad68k.h @@ -109,3 +109,6 @@ Boston, MA 02111-1307, USA. */ #define HAVE_PTYS /* we do have PTYs if we have TCP */ #define HAVE_SOCKETS /* we do have sockets if we have TCP */ #define LIBS_SYSTEM -lsocket /* get TCP networking functions */ + +/* arch-tag: e0c09754-b0f2-48da-a8a5-aee3c94838f4 + (do not change this comment) */ diff --git a/src/m/tahoe.h b/src/m/tahoe.h index 343247d0529..42741e25cb6 100644 --- a/src/m/tahoe.h +++ b/src/m/tahoe.h @@ -66,3 +66,6 @@ NOTE-END */ /* This triggers some stuff to avoid a compiler bug */ #define TAHOE_REGISTER_BUG + +/* arch-tag: dd452693-80e1-413f-a164-0141eb68d831 + (do not change this comment) */ diff --git a/src/m/tandem-s2.h b/src/m/tandem-s2.h index 92e9ebfbb35..b22f9bb66af 100644 --- a/src/m/tandem-s2.h +++ b/src/m/tandem-s2.h @@ -19,3 +19,6 @@ /* Correct some library file names. */ #define START_FILES pre-crt0.o /usr/lib/crt1.o1.31 #define LIB_STANDARD -lbsd -lc /usr/lib/crtn.o1.31 + +/* arch-tag: ae34a1a6-6408-4b23-a6d3-ce4e8f124916 + (do not change this comment) */ diff --git a/src/m/targon31.h b/src/m/targon31.h index 7c44f12e177..afc72f4e0ee 100644 --- a/src/m/targon31.h +++ b/src/m/targon31.h @@ -92,3 +92,6 @@ Boston, MA 02111-1307, USA. */ #define SEGMENT_MASK 0xffff #define SWITCH_ENUM_BUG 1 + +/* arch-tag: f2438018-7d4e-4be5-b368-4bf342b7785b + (do not change this comment) */ diff --git a/src/m/tek4300.h b/src/m/tek4300.h index d402022a034..34b160ba6da 100644 --- a/src/m/tek4300.h +++ b/src/m/tek4300.h @@ -99,3 +99,6 @@ Boston, MA 02111-1307, USA. */ /* Process groups work in the traditional BSD manner. */ #define BSD_PGRPS + +/* arch-tag: afa06e53-094c-4a19-9219-155f8ba4bbcc + (do not change this comment) */ diff --git a/src/m/tekxd88.h b/src/m/tekxd88.h index 2e1fa20d371..a30bbdd8d6c 100644 --- a/src/m/tekxd88.h +++ b/src/m/tekxd88.h @@ -111,3 +111,6 @@ Boston, MA 02111-1307, USA. */ /* We need this to get dumping to work */ #define KEEP_OLD_TEXT_SCNPTR + +/* arch-tag: fd3cebc3-2aed-4f8c-be9b-f37331c6e0ff + (do not change this comment) */ diff --git a/src/m/template.h b/src/m/template.h index 6def690cd98..914daa3047c 100644 --- a/src/m/template.h +++ b/src/m/template.h @@ -109,3 +109,6 @@ Boston, MA 02111-1307, USA. */ If you've just fixed a problem in an existing configuration file, you should also check `etc/MACHINES' to make sure its descriptions of known problems in that configuration should be updated. */ + +/* arch-tag: d7dae0a9-4f99-4939-bef9-5738e1f33955 + (do not change this comment) */ diff --git a/src/m/tower32.h b/src/m/tower32.h index 307d2b93e33..947e495aa20 100644 --- a/src/m/tower32.h +++ b/src/m/tower32.h @@ -109,3 +109,6 @@ Boston, MA 02111-1307, USA. */ #include <asld.h> #define EXEC_MAGIC AOUT1MAGIC #define EXEC_PAGESIZE DATACLICK + +/* arch-tag: a08e7dea-d48e-44cc-b60d-c7f2e5187ff5 + (do not change this comment) */ diff --git a/src/m/tower32v3.h b/src/m/tower32v3.h index 3d54366aa94..fbd7e032a38 100644 --- a/src/m/tower32v3.h +++ b/src/m/tower32v3.h @@ -107,3 +107,6 @@ Boston, MA 02111-1307, USA. */ /* The OS needs stream.h+ptem.h included in sysdep.c. */ #define NO_SIOCTL_H #define NEED_PTEM_H + +/* arch-tag: 3dff1355-7cb6-49e3-8834-85a369e4ea8f + (do not change this comment) */ diff --git a/src/m/ustation.h b/src/m/ustation.h index 17d59df0d02..b03a3555352 100644 --- a/src/m/ustation.h +++ b/src/m/ustation.h @@ -126,3 +126,6 @@ Boston, MA 02111-1307, USA. */ #define BROKEN_SIGIO #define BROKEN_SIGTSTP + +/* arch-tag: 797f1d3e-3077-4eee-a81b-03fcf3a988fe + (do not change this comment) */ diff --git a/src/m/vax.h b/src/m/vax.h index eace9f7e144..2e9d4738b64 100644 --- a/src/m/vax.h +++ b/src/m/vax.h @@ -113,3 +113,6 @@ NOTE-END */ #ifdef BSD4_2 #define HAVE_FTIME #endif + +/* arch-tag: 508bdf7a-01a0-4ce0-8eba-0704d0df55a0 + (do not change this comment) */ diff --git a/src/m/wicat.h b/src/m/wicat.h index 0a9596cd15c..bca10df352d 100644 --- a/src/m/wicat.h +++ b/src/m/wicat.h @@ -131,3 +131,6 @@ Boston, MA 02111-1307, USA. */ #undef TERMINFO #define LIBS_TERMCAP select.o -ltermlib #endif + +/* arch-tag: b181c512-0275-4d25-9bbc-be0c8ca7bcad + (do not change this comment) */ diff --git a/src/m/windowsnt.h b/src/m/windowsnt.h index 4188a7032ec..701e6e21e1b 100644 --- a/src/m/windowsnt.h +++ b/src/m/windowsnt.h @@ -119,3 +119,6 @@ Boston, MA 02111-1307, USA. */ If you've just fixed a problem in an existing configuration file, you should also check `etc/MACHINES' to make sure its descriptions of known problems in that configuration should be updated. */ + +/* arch-tag: ed6dc0c1-5c01-49df-befd-c25dfadfb8cf + (do not change this comment) */ diff --git a/src/m/xps100.h b/src/m/xps100.h index 26cec523741..617b0a9c1d7 100644 --- a/src/m/xps100.h +++ b/src/m/xps100.h @@ -92,3 +92,6 @@ Boston, MA 02111-1307, USA. */ #define LIB_STANDARD -lc #define LD_SWITCH_MACHINE -X #define SECTION_ALIGNMENT (0x3ff) + +/* arch-tag: 42316eb5-74b2-4762-970a-e372c6a2783d + (do not change this comment) */ diff --git a/src/mac.c b/src/mac.c index ce2e4242493..9f3455ab5dc 100644 --- a/src/mac.c +++ b/src/mac.c @@ -30,6 +30,7 @@ Boston, MA 02111-1307, USA. */ #include <sys/stat.h> #include <string.h> #include <pwd.h> +#include <grp.h> #include <sys/param.h> #include <stdlib.h> #include <fcntl.h> @@ -1164,6 +1165,13 @@ static struct passwd my_passwd = my_passwd_dir, }; +static struct group my_group = +{ + /* There are no groups on the mac, so we just return "root" as the + group name. */ + "root", +}; + /* Initialized by main () in macterm.c to pathname of emacs directory. */ @@ -1258,6 +1266,13 @@ getpwuid (uid_t uid) } +struct group * +getgrgid (gid_t gid) +{ + return &my_group; +} + + struct passwd * getpwnam (const char *name) { @@ -2988,3 +3003,6 @@ syms_of_mac () defsubr (&Smac_file_name_to_posix); defsubr (&Sposix_file_name_to_mac); } + +/* arch-tag: 29d30c1f-0c6b-4f88-8a6d-0558d7f9dbff + (do not change this comment) */ diff --git a/src/macfns.c b/src/macfns.c index 003ae084c2c..dbb8adb3fe1 100644 --- a/src/macfns.c +++ b/src/macfns.c @@ -54,6 +54,8 @@ static unsigned char gray_bits[] = { /*#include <commdlg.h> #include <shellapi.h>*/ #include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> #include <stdlib.h> #include <string.h> @@ -62,32 +64,7 @@ static unsigned char gray_bits[] = { #endif #ifdef MAC_OSX -#undef mktime -#undef DEBUG -#undef Z -#undef free -#undef malloc -#undef realloc -/* Macros max and min defined in lisp.h conflict with those in - precompiled header Carbon.h. */ -#undef max -#undef min -#undef init_process -#include <Carbon/Carbon.h> -#undef Z -#define Z (current_buffer->text->z) -#undef free -#define free unexec_free -#undef malloc -#define malloc unexec_malloc -#undef realloc -#define realloc unexec_realloc -#undef min -#define min(a, b) ((a) < (b) ? (a) : (b)) -#undef max -#define max(a, b) ((a) > (b) ? (a) : (b)) -#undef init_process -#define init_process emacs_init_process +#include <QuickTime/QuickTime.h> #else /* not MAC_OSX */ #include <Windows.h> #include <Gestalt.h> @@ -140,10 +117,6 @@ static int mac_in_use; Lisp_Object Vx_no_window_manager; -/* Search path for bitmap files. */ - -Lisp_Object Vx_bitmap_file_path; - /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */ Lisp_Object Vx_pixel_size_width_font_regexp; @@ -186,7 +159,6 @@ Lisp_Object Vx_pixel_size_width_font_regexp; Lisp_Object Qnone; Lisp_Object Qsuppress_icon; Lisp_Object Qundefined_color; -Lisp_Object Qcenter; Lisp_Object Qcancel_timer; Lisp_Object Qhyper; Lisp_Object Qsuper; @@ -200,15 +172,6 @@ extern Lisp_Object Vwindow_system_version; extern int mac_initialized; -/* Functions in macterm.c. */ -extern void x_set_window_size (struct frame *, int, int, int); -extern void x_make_frame_visible (struct frame *); -extern struct mac_display_info *mac_term_init (Lisp_Object, char *, char *); -extern struct font_info *x_get_font_info (FRAME_PTR, int); -extern struct font_info *x_load_font (struct frame *, char *, int); -extern void x_find_ccl_program (struct font_info *); -extern struct font_info *x_query_font (struct frame *, char *); -extern void mac_initialize (); /* compare two strings ignoring case */ @@ -338,227 +301,7 @@ x_window_to_frame (dpyinfo, wdesc) } - -/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap - id, which is just an int that this section returns. Bitmaps are - reference counted so they can be shared among frames. - - Bitmap indices are guaranteed to be > 0, so a negative number can - be used to indicate no bitmap. - - If you use x_create_bitmap_from_data, then you must keep track of - the bitmaps yourself. That is, creating a bitmap from the same - data more than once will not be caught. */ - - -/* Functions to access the contents of a bitmap, given an id. */ - -int -x_bitmap_height (f, id) - FRAME_PTR f; - int id; -{ - return FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].height; -} - -int -x_bitmap_width (f, id) - FRAME_PTR f; - int id; -{ - return FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].width; -} - -#if 0 /* MAC_TODO : not used anywhere (?) */ -int -x_bitmap_pixmap (f, id) - FRAME_PTR f; - int id; -{ - return (int) FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap; -} -#endif - -/* Allocate a new bitmap record. Returns index of new record. */ - -static int -x_allocate_bitmap_record (f) - FRAME_PTR f; -{ - struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); - int i; - - if (dpyinfo->bitmaps == NULL) - { - dpyinfo->bitmaps_size = 10; - dpyinfo->bitmaps = (struct mac_bitmap_record *) - xmalloc (dpyinfo->bitmaps_size * sizeof (struct mac_bitmap_record)); - dpyinfo->bitmaps_last = 1; - return 1; - } - - if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size) - return ++dpyinfo->bitmaps_last; - - for (i = 0; i < dpyinfo->bitmaps_size; ++i) - if (dpyinfo->bitmaps[i].refcount == 0) - return i + 1; - - dpyinfo->bitmaps_size *= 2; - dpyinfo->bitmaps = (struct mac_bitmap_record *) - xrealloc (dpyinfo->bitmaps, - dpyinfo->bitmaps_size * sizeof (struct mac_bitmap_record)); - return ++dpyinfo->bitmaps_last; -} - -/* Add one reference to the reference count of the bitmap with id - ID. */ - -void -x_reference_bitmap (f, id) - FRAME_PTR f; - int id; -{ - ++FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].refcount; -} - -/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at - BITS. */ - -int -x_create_bitmap_from_data (f, bits, width, height) - struct frame *f; - char *bits; - unsigned int width, height; -{ - struct x_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); - int id; - - /* MAC_TODO: for now fail if width is not mod 16 (toolbox requires it) */ - - id = x_allocate_bitmap_record (f); - - if (width % 16 != 0) - return -1; - - dpyinfo->bitmaps[id - 1].bitmap_data = (char *) xmalloc (height * width); - if (! dpyinfo->bitmaps[id - 1].bitmap_data) - return -1; - - bcopy (bits, dpyinfo->bitmaps[id - 1].bitmap_data, height * width); - - dpyinfo->bitmaps[id - 1].refcount = 1; - dpyinfo->bitmaps[id - 1].height = height; - dpyinfo->bitmaps[id - 1].width = width; - - return id; -} - -/* Create bitmap from file FILE for frame F. */ - -int -x_create_bitmap_from_file (f, file) - struct frame *f; - Lisp_Object file; -{ - return -1; -#if 0 /* MAC_TODO : bitmap support */ - struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f); - unsigned int width, height; - HBITMAP bitmap; - int xhot, yhot, result, id; - Lisp_Object found; - int fd; - char *filename; - HINSTANCE hinst; - - /* Look for an existing bitmap with the same name. */ - for (id = 0; id < dpyinfo->bitmaps_last; ++id) - { - if (dpyinfo->bitmaps[id].refcount - && dpyinfo->bitmaps[id].file - && !strcmp (dpyinfo->bitmaps[id].file, (char *) SDATA (file))) - { - ++dpyinfo->bitmaps[id].refcount; - return id + 1; - } - } - - /* Search bitmap-file-path for the file, if appropriate. */ - fd = openp (Vx_bitmap_file_path, file, "", &found, Qnil); - if (fd < 0) - return -1; - /* LoadLibraryEx won't handle special files handled by Emacs handler. */ - if (fd == 0) - return -1; - emacs_close (fd); - - filename = (char *) SDATA (found); - - hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE); - - if (hinst == NULL) - return -1; - - - result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), - filename, &width, &height, &bitmap, &xhot, &yhot); - if (result != BitmapSuccess) - return -1; - - id = x_allocate_bitmap_record (f); - dpyinfo->bitmaps[id - 1].pixmap = bitmap; - dpyinfo->bitmaps[id - 1].refcount = 1; - dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (SCHARS (file) + 1); - dpyinfo->bitmaps[id - 1].depth = 1; - dpyinfo->bitmaps[id - 1].height = height; - dpyinfo->bitmaps[id - 1].width = width; - strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file)); - - return id; -#endif /* MAC_TODO */ -} - -/* Remove reference to bitmap with id number ID. */ - -void -x_destroy_bitmap (f, id) - FRAME_PTR f; - int id; -{ - struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); - - if (id > 0) - { - --dpyinfo->bitmaps[id - 1].refcount; - if (dpyinfo->bitmaps[id - 1].refcount == 0) - { - BLOCK_INPUT; - dpyinfo->bitmaps[id - 1].bitmap_data = NULL; - UNBLOCK_INPUT; - } - } -} - -/* Free all the bitmaps for the display specified by DPYINFO. */ - -static void -x_destroy_all_bitmaps (dpyinfo) - struct mac_display_info *dpyinfo; -{ - int i; - for (i = 0; i < dpyinfo->bitmaps_last; i++) - if (dpyinfo->bitmaps[i].refcount > 0) - xfree (dpyinfo->bitmaps[i].bitmap_data); - dpyinfo->bitmaps_last = 0; -} - -/* Connect the frame-parameter names for W32 frames - to the ways of passing the parameter values to the window system. - - The name of a parameter, as a Lisp symbol, - has an `x-frame-parameter' property which is an integer in Lisp - but can be interpreted as an `enum x_frame_parm' in C. */ +static Lisp_Object unwind_create_frame P_ ((Lisp_Object)); void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object)); void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object)); @@ -581,7 +324,6 @@ static Lisp_Object x_default_scroll_bar_color_parameter P_ ((struct frame *, Lisp_Object, char *, char *, int)); - /* Store the screen positions of frame F into XPTR and YPTR. These are the positions of the containing window manager window, not Emacs's own window. */ @@ -1382,7 +1124,7 @@ colormap_t mac_color_map[] = { RGB_TO_ULONG(144, 238, 144), "LightGreen" } }; -unsigned long +Lisp_Object mac_color_map_lookup (colorname) char *colorname; { @@ -1394,7 +1136,7 @@ mac_color_map_lookup (colorname) for (i = 0; i < sizeof (mac_color_map) / sizeof (mac_color_map[0]); i++) if (stricmp (colorname, mac_color_map[i].name) == 0) { - ret = mac_color_map[i].color; + ret = make_number (mac_color_map[i].color); break; } @@ -1463,7 +1205,7 @@ x_to_mac_color (colorname) if (i == 2) { UNBLOCK_INPUT; - return (colorval); + return make_number (colorval); } color = end; } @@ -1516,7 +1258,7 @@ x_to_mac_color (colorname) if (*end != '\0') break; UNBLOCK_INPUT; - return (colorval); + return make_number (colorval); } if (*end != '/') break; @@ -1557,7 +1299,7 @@ x_to_mac_color (colorname) if (*end != '\0') break; UNBLOCK_INPUT; - return (colorval); + return make_number (colorval); } if (*end != '/') break; @@ -1616,9 +1358,9 @@ mac_defined_color (f, color, color_def, alloc) } color_def->pixel = mac_color_ref; - color_def->red = RED_FROM_ULONG (mac_color_ref); - color_def->green = GREEN_FROM_ULONG (mac_color_ref); - color_def->blue = BLUE_FROM_ULONG (mac_color_ref); + color_def->red = RED16_FROM_ULONG (mac_color_ref); + color_def->green = GREEN16_FROM_ULONG (mac_color_ref); + color_def->blue = BLUE16_FROM_ULONG (mac_color_ref); return 1; } @@ -1649,8 +1391,7 @@ x_decode_color (f, arg, def) return WHITE_PIX_DEFAULT (f); #if 0 - if ((FRAME_MAC_DISPLAY_INFO (f)->n_planes - * FRAME_MAC_DISPLAY_INFO (f)->n_cbits) == 1) + if (FRAME_MAC_DISPLAY_INFO (f)->n_planes) == 1) return def; #endif @@ -1674,8 +1415,11 @@ x_set_foreground_color (f, arg, oldval) struct frame *f; Lisp_Object arg, oldval; { - FRAME_FOREGROUND_PIXEL (f) - = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); + unsigned long fg, old_fg; + + fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); + old_fg = FRAME_FOREGROUND_PIXEL (f); + FRAME_FOREGROUND_PIXEL (f) = fg; if (FRAME_MAC_WINDOW (f) != 0) { @@ -1856,36 +1600,42 @@ x_set_cursor_color (f, arg, oldval) struct frame *f; Lisp_Object arg, oldval; { - unsigned long fore_pixel; + unsigned long fore_pixel, pixel; if (!NILP (Vx_cursor_fore_pixel)) fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel, WHITE_PIX_DEFAULT (f)); else fore_pixel = FRAME_BACKGROUND_PIXEL (f); - f->output_data.mac->cursor_pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); + + pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); /* Make sure that the cursor color differs from the background color. */ - if (f->output_data.mac->cursor_pixel == FRAME_BACKGROUND_PIXEL (f)) + if (pixel == FRAME_BACKGROUND_PIXEL (f)) { - f->output_data.mac->cursor_pixel = f->output_data.mac->mouse_pixel; - if (f->output_data.mac->cursor_pixel == fore_pixel) + pixel = f->output_data.mac->mouse_pixel; + if (pixel == fore_pixel) fore_pixel = FRAME_BACKGROUND_PIXEL (f); } - FRAME_FOREGROUND_PIXEL (f) = fore_pixel; -#if 0 /* MAC_TODO: cannot figure out what to do (wrong number of params) */ + f->output_data.mac->cursor_foreground_pixel = fore_pixel; + f->output_data.mac->cursor_pixel = pixel; + if (FRAME_MAC_WINDOW (f) != 0) { + BLOCK_INPUT; + /* Update frame's cursor_gc. */ + f->output_data.mac->cursor_gc->foreground = fore_pixel; + f->output_data.mac->cursor_gc->background = pixel; + + UNBLOCK_INPUT; + if (FRAME_VISIBLE_P (f)) { - BLOCK_INPUT; - display_and_set_cursor (f, 0); - display_and_set_cursor (f, 1); - UNBLOCK_INPUT; + x_update_cursor (f, 0); + x_update_cursor (f, 1); } } -#endif update_face_from_frame_parameter (f, Qcursor_color, arg); } @@ -1893,11 +1643,13 @@ x_set_cursor_color (f, arg, oldval) /* Set the border-color of frame F to pixel value PIX. Note that this does not fully take effect if done before F has a window. */ + void x_set_border_pixel (f, pix) struct frame *f; int pix; { + f->output_data.mac->border_pixel = pix; if (FRAME_MAC_WINDOW (f) != 0 && f->border_width > 0) @@ -1926,6 +1678,7 @@ x_set_border_color (f, arg, oldval) update_face_from_frame_parameter (f, Qborder_color, arg); } + void x_set_cursor_type (f, arg, oldval) FRAME_PTR f; @@ -1933,9 +1686,8 @@ x_set_cursor_type (f, arg, oldval) { set_frame_cursor_types (f, arg); - /* Make sure the cursor gets redrawn. This is overkill, but how - often do people change cursor types? */ - update_mode_lines++; + /* Make sure the cursor gets redrawn. */ + cursor_type_changed = 1; } #if 0 /* MAC_TODO: really no icon for Mac */ @@ -2597,7 +2349,7 @@ x_make_gc (f) BLOCK_INPUT; - /* Create the GC's of this frame. + /* Create the GCs of this frame. Note that many default values are used. */ /* Normal video */ @@ -2629,10 +2381,104 @@ x_make_gc (f) f->output_data.mac->white_relief.gc = 0; f->output_data.mac->black_relief.gc = 0; +#if 0 + /* Create the gray border tile used when the pointer is not in + the frame. Since this depends on the frame's pixel values, + this must be done on a per-frame basis. */ + f->output_data.x->border_tile + = (XCreatePixmapFromBitmapData + (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window, + gray_bits, gray_width, gray_height, + f->output_data.x->foreground_pixel, + f->output_data.x->background_pixel, + DefaultDepth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f)))); +#endif + + UNBLOCK_INPUT; +} + + +/* Free what was was allocated in x_make_gc. */ + +void +x_free_gcs (f) + struct frame *f; +{ + Display *dpy = FRAME_MAC_DISPLAY (f); + + BLOCK_INPUT; + + if (f->output_data.mac->normal_gc) + { + XFreeGC (dpy, f->output_data.mac->normal_gc); + f->output_data.mac->normal_gc = 0; + } + + if (f->output_data.mac->reverse_gc) + { + XFreeGC (dpy, f->output_data.mac->reverse_gc); + f->output_data.mac->reverse_gc = 0; + } + + if (f->output_data.mac->cursor_gc) + { + XFreeGC (dpy, f->output_data.mac->cursor_gc); + f->output_data.mac->cursor_gc = 0; + } + +#if 0 + if (f->output_data.mac->border_tile) + { + XFreePixmap (dpy, f->output_data.mac->border_tile); + f->output_data.mac->border_tile = 0; + } +#endif + + if (f->output_data.mac->white_relief.gc) + { + XFreeGC (dpy, f->output_data.mac->white_relief.gc); + f->output_data.mac->white_relief.gc = 0; + } + + if (f->output_data.mac->black_relief.gc) + { + XFreeGC (dpy, f->output_data.mac->black_relief.gc); + f->output_data.mac->black_relief.gc = 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, doc: /* Make a new window, which is called a \"frame\" in Emacs terms. @@ -2736,10 +2582,7 @@ This function is an internal primitive--use `make-frame' instead. */) FRAME_FONTSET (f) = -1; f->output_data.mac->scroll_bar_foreground_pixel = -1; f->output_data.mac->scroll_bar_background_pixel = -1; - -#if 0 - FRAME_FONTSET (f) = -1; -#endif + record_unwind_protect (unwind_create_frame, frame); f->icon_name = mac_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING); @@ -2790,17 +2633,18 @@ This function is an internal primitive--use `make-frame' instead. */) /* First, try whatever font the caller has specified. */ if (STRINGP (font)) { - tem = Fquery_fontset (font, Qnil); - if (STRINGP (tem)) - font = x_new_fontset (f, SDATA (tem)); - else - font = x_new_font (f, SDATA (font)); + tem = Fquery_fontset (font, Qnil); + if (STRINGP (tem)) + font = x_new_fontset (f, SDATA (tem)); + else + font = x_new_font (f, SDATA (font)); } + /* Try out a font which we hope has bold and italic variations. */ if (! STRINGP (font)) font = x_new_font (f, "-ETL-fixed-medium-r-*--*-160-*-*-*-*-iso8859-1"); /* If those didn't work, look for something which will at least work. */ - if (!STRINGP (font)) + if (! STRINGP (font)) font = x_new_font (f, "-*-monaco-*-12-*-mac-roman"); if (! STRINGP (font)) font = x_new_font (f, "-*-courier-*-10-*-mac-roman"); @@ -3011,12 +2855,9 @@ DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0, { Lisp_Object rgb[3]; - rgb[0] = make_number ((RED_FROM_ULONG (foo.pixel) << 8) - | RED_FROM_ULONG (foo.pixel)); - rgb[1] = make_number ((GREEN_FROM_ULONG (foo.pixel) << 8) - | GREEN_FROM_ULONG (foo.pixel)); - rgb[2] = make_number ((BLUE_FROM_ULONG (foo.pixel) << 8) - | BLUE_FROM_ULONG (foo.pixel)); + rgb[0] = make_number (foo.red); + rgb[1] = make_number (foo.green); + rgb[2] = make_number (foo.blue); return Flist (3, rgb); } else @@ -3030,7 +2871,7 @@ DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0, { struct mac_display_info *dpyinfo = check_x_display_info (display); - if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2) + if (!dpyinfo->color_p) return Qnil; return Qt; @@ -3048,7 +2889,7 @@ If omitted or nil, that stands for the selected frame's display. */) { struct mac_display_info *dpyinfo = check_x_display_info (display); - if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1) + if (dpyinfo->n_planes <= 1) return Qnil; return Qt; @@ -3093,7 +2934,7 @@ If omitted or nil, that stands for the selected frame's display. */) { struct mac_display_info *dpyinfo = check_x_display_info (display); - return make_number (dpyinfo->n_planes * dpyinfo->n_cbits); + return make_number (dpyinfo->n_planes); } DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells, @@ -3108,7 +2949,7 @@ If omitted or nil, that stands for the selected frame's display. */) struct mac_display_info *dpyinfo = check_x_display_info (display); /* MAC_TODO: check whether this is right */ - return make_number ((unsigned long) (pow (2, dpyinfo->n_cbits))); + return make_number (dpyinfo->n_planes >= 8 ? 256 : 1 << dpyinfo->n_planes - 1); } DEFUN ("x-server-max-request-size", Fx_server_max_request_size, @@ -3448,4361 +3289,29 @@ If DISPLAY is omitted or nil, that stands for the selected frame's display. */) /*********************************************************************** - Image types - ***********************************************************************/ - -/* Value is the number of elements of vector VECTOR. */ - -#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR)) - -/* List of supported image types. Use define_image_type to add new - types. Use lookup_image_type to find a type for a given symbol. */ - -static struct image_type *image_types; - -/* The symbol `image' which is the car of the lists used to represent - images in Lisp. */ - -extern Lisp_Object Qimage; - -/* The symbol `xbm' which is used as the type symbol for XBM images. */ - -Lisp_Object Qxbm; - -/* Keywords. */ - -extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile; -extern Lisp_Object QCdata, QCtype; -Lisp_Object QCascent, QCmargin, QCrelief; -Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask; -Lisp_Object QCindex; - -/* Other symbols. */ - -Lisp_Object Qlaplace; - -/* Time in seconds after which images should be removed from the cache - if not displayed. */ - -Lisp_Object Vimage_cache_eviction_delay; - -/* Function prototypes. */ - -static void define_image_type P_ ((struct image_type *type)); -static struct image_type *lookup_image_type P_ ((Lisp_Object symbol)); -static void image_error P_ ((char *format, Lisp_Object, Lisp_Object)); -static void x_laplace P_ ((struct frame *, struct image *)); -static int x_build_heuristic_mask P_ ((struct frame *, struct image *, - Lisp_Object)); - - -/* Define a new image type from TYPE. This adds a copy of TYPE to - image_types and adds the symbol *TYPE->type to Vimage_types. */ - -static void -define_image_type (type) - struct image_type *type; -{ - /* Make a copy of TYPE to avoid a bus error in a dumped Emacs. - The initialized data segment is read-only. */ - struct image_type *p = (struct image_type *) xmalloc (sizeof *p); - bcopy (type, p, sizeof *p); - p->next = image_types; - image_types = p; - Vimage_types = Fcons (*p->type, Vimage_types); -} - - -/* Look up image type SYMBOL, and return a pointer to its image_type - structure. Value is null if SYMBOL is not a known image type. */ - -static INLINE struct image_type * -lookup_image_type (symbol) - Lisp_Object symbol; -{ - struct image_type *type; - - for (type = image_types; type; type = type->next) - if (EQ (symbol, *type->type)) - break; - - return type; -} - - -/* Value is non-zero if OBJECT is a valid Lisp image specification. A - valid image specification is a list whose car is the symbol - `image', and whose rest is a property list. The property list must - contain a value for key `:type'. That value must be the name of a - supported image type. The rest of the property list depends on the - image type. */ - -int -valid_image_p (object) - Lisp_Object object; -{ - int valid_p = 0; - - 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); - } - - return valid_p; -} - - -/* Log error message with format string FORMAT and argument ARG. - Signaling an error, e.g. when an image cannot be loaded, is not a - good idea because this would interrupt redisplay, and the error - message display would lead to another redisplay. This function - therefore simply displays a message. */ - -static void -image_error (format, arg1, arg2) - char *format; - Lisp_Object arg1, arg2; -{ - add_to_log (format, arg1, arg2); -} - - - -/*********************************************************************** - Image specifications - ***********************************************************************/ - -enum image_value_type -{ - IMAGE_DONT_CHECK_VALUE_TYPE, - IMAGE_STRING_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, - IMAGE_FUNCTION_VALUE, - IMAGE_NUMBER_VALUE, - IMAGE_BOOL_VALUE -}; - -/* Structure used when parsing image specifications. */ - -struct image_keyword -{ - /* Name of keyword. */ - char *name; - - /* The type of value allowed. */ - enum image_value_type type; - - /* Non-zero means key must be present. */ - int mandatory_p; - - /* Used to recognize duplicate keywords in a property list. */ - int count; - - /* The value that was found. */ - Lisp_Object value; -}; - - -static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *, - int, Lisp_Object)); -static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *)); - - -/* Parse image spec SPEC according to KEYWORDS. A valid image spec - has the format (image KEYWORD VALUE ...). One of the keyword/ - value pairs must be `:type TYPE'. KEYWORDS is a vector of - image_keywords structures of size NKEYWORDS describing other - allowed keyword/value pairs. Value is non-zero if SPEC is valid. */ - -static int -parse_image_spec (spec, keywords, nkeywords, type) - Lisp_Object spec; - struct image_keyword *keywords; - int nkeywords; - Lisp_Object type; -{ - int i; - Lisp_Object plist; - - if (!CONSP (spec) || !EQ (XCAR (spec), Qimage)) - return 0; - - plist = XCDR (spec); - while (CONSP (plist)) - { - Lisp_Object key, value; - - /* First element of a pair must be a symbol. */ - key = XCAR (plist); - plist = XCDR (plist); - if (!SYMBOLP (key)) - return 0; - - /* There must follow a value. */ - if (!CONSP (plist)) - return 0; - value = XCAR (plist); - plist = XCDR (plist); - - /* Find key in KEYWORDS. Error if not found. */ - for (i = 0; i < nkeywords; ++i) - if (strcmp (keywords[i].name, SDATA (SYMBOL_NAME (key))) == 0) - break; - - if (i == nkeywords) - continue; - - /* Record that we recognized the keyword. If a keywords - was found more than once, it's an error. */ - keywords[i].value = value; - ++keywords[i].count; - - if (keywords[i].count > 1) - return 0; - - /* Check type of value against allowed type. */ - switch (keywords[i].type) - { - case IMAGE_STRING_VALUE: - if (!STRINGP (value)) - return 0; - break; - - case IMAGE_SYMBOL_VALUE: - if (!SYMBOLP (value)) - return 0; - break; - - case IMAGE_POSITIVE_INTEGER_VALUE: - if (!INTEGERP (value) || XINT (value) <= 0) - 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; - else if (INTEGERP (value) - && XINT (value) >= 0 - && XINT (value) <= 100) - break; - return 0; - - case IMAGE_NON_NEGATIVE_INTEGER_VALUE: - if (!INTEGERP (value) || XINT (value) < 0) - return 0; - break; - - case IMAGE_DONT_CHECK_VALUE_TYPE: - break; - - case IMAGE_FUNCTION_VALUE: - value = indirect_function (value); - if (SUBRP (value) - || COMPILEDP (value) - || (CONSP (value) && EQ (XCAR (value), Qlambda))) - break; - return 0; - - case IMAGE_NUMBER_VALUE: - if (!INTEGERP (value) && !FLOATP (value)) - return 0; - break; - - case IMAGE_INTEGER_VALUE: - if (!INTEGERP (value)) - return 0; - break; - - case IMAGE_BOOL_VALUE: - if (!NILP (value) && !EQ (value, Qt)) - return 0; - break; - - default: - abort (); - break; - } - - if (EQ (key, QCtype) && !EQ (type, value)) - return 0; - } - - /* Check that all mandatory fields are present. */ - for (i = 0; i < nkeywords; ++i) - if (keywords[i].mandatory_p && keywords[i].count == 0) - return 0; - - return NILP (plist); -} - - -/* Return the value of KEY in image specification SPEC. Value is nil - if KEY is not present in SPEC. if FOUND is not null, set *FOUND - to 1 if KEY was found in SPEC, set it to 0 otherwise. */ - -static Lisp_Object -image_spec_value (spec, key, found) - Lisp_Object spec, key; - int *found; -{ - Lisp_Object tail; - - xassert (valid_image_p (spec)); - - for (tail = XCDR (spec); - CONSP (tail) && CONSP (XCDR (tail)); - tail = XCDR (XCDR (tail))) - { - if (EQ (XCAR (tail), key)) - { - if (found) - *found = 1; - return XCAR (XCDR (tail)); - } - } - - if (found) - *found = 0; - return Qnil; -} - - - - -/*********************************************************************** - Image type independent image structures - ***********************************************************************/ - -static struct image *make_image P_ ((Lisp_Object spec, unsigned hash)); -static void free_image P_ ((struct frame *f, struct image *img)); - - -/* Allocate and return a new image structure for image specification - SPEC. SPEC has a hash value of HASH. */ - -static struct image * -make_image (spec, hash) - Lisp_Object spec; - unsigned hash; -{ - struct image *img = (struct image *) xmalloc (sizeof *img); - - xassert (valid_image_p (spec)); - bzero (img, sizeof *img); - img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL)); - xassert (img->type != NULL); - img->spec = spec; - img->data.lisp_val = Qnil; - img->ascent = DEFAULT_IMAGE_ASCENT; - img->hash = hash; - return img; -} - - -/* Free image IMG which was used on frame F, including its resources. */ - -static void -free_image (f, img) - struct frame *f; - struct image *img; -{ - if (img) - { - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - - /* Remove IMG from the hash table of its cache. */ - if (img->prev) - img->prev->next = img->next; - else - c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next; - - if (img->next) - img->next->prev = img->prev; - - c->images[img->id] = NULL; - - /* Free resources, then free IMG. */ - img->type->free (f, img); - xfree (img); - } -} - - -/* Prepare image IMG for display on frame F. Must be called before - drawing an image. */ - -void -prepare_image_for_display (f, img) - struct frame *f; - struct image *img; -{ - EMACS_TIME t; - - /* We're about to display IMG, so set its timestamp to `now'. */ - EMACS_GET_TIME (t); - img->timestamp = EMACS_SECS (t); - - /* If IMG doesn't have a pixmap yet, load it now, using the image - type dependent loader function. */ - if (img->pixmap == 0 && !img->load_failed_p) - img->load_failed_p = img->type->load (f, img) == 0; -} - - -/* Value is the number of pixels for the ascent of image IMG when - drawn in face FACE. */ - -int -image_ascent (img, face) - struct image *img; - struct face *face; -{ - int height = img->height + img->vmargin; - int ascent; - - if (img->ascent == CENTERED_IMAGE_ASCENT) - { - if (face->font) - ascent = height / 2 - (FONT_DESCENT(face->font) - - FONT_BASE(face->font)) / 2; - else - ascent = height / 2; - } - else - ascent = height * img->ascent / 100.0; - - return ascent; -} - - - -/*********************************************************************** - Helper functions for X image types - ***********************************************************************/ - -static void x_clear_image P_ ((struct frame *f, struct image *img)); -static unsigned long x_alloc_image_color P_ ((struct frame *f, - struct image *img, - Lisp_Object color_name, - unsigned long dflt)); - -/* Free X resources of image IMG which is used on frame F. */ - -static void -x_clear_image (f, img) - struct frame *f; - struct image *img; -{ -#if 0 /* MAC_TODO: W32 image support */ - - if (img->pixmap) - { - BLOCK_INPUT; - XFreePixmap (NULL, img->pixmap); - img->pixmap = 0; - UNBLOCK_INPUT; - } - - if (img->ncolors) - { - int class = FRAME_W32_DISPLAY_INFO (f)->visual->class; - - /* If display has an immutable color map, freeing colors is not - necessary and some servers don't allow it. So don't do it. */ - if (class != StaticColor - && class != StaticGray - && class != TrueColor) - { - Colormap cmap; - BLOCK_INPUT; - cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen); - XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors, - img->ncolors, 0); - UNBLOCK_INPUT; - } - - xfree (img->colors); - img->colors = NULL; - img->ncolors = 0; - } -#endif /* MAC_TODO */ -} - - -/* Allocate color COLOR_NAME for image IMG on frame F. If color - cannot be allocated, use DFLT. Add a newly allocated color to - IMG->colors, so that it can be freed again. Value is the pixel - color. */ - -static unsigned long -x_alloc_image_color (f, img, color_name, dflt) - struct frame *f; - struct image *img; - Lisp_Object color_name; - unsigned long dflt; -{ -#if 0 /* MAC_TODO: allocing colors. */ - XColor color; - unsigned long result; - - xassert (STRINGP (color_name)); - - if (w32_defined_color (f, SDATA (color_name), &color, 1)) - { - /* This isn't called frequently so we get away with simply - reallocating the color vector to the needed size, here. */ - ++img->ncolors; - img->colors = - (unsigned long *) xrealloc (img->colors, - img->ncolors * sizeof *img->colors); - img->colors[img->ncolors - 1] = color.pixel; - result = color.pixel; - } - else - result = dflt; - return result; -#endif /* MAC_TODO */ - return 0; -} - - - -/*********************************************************************** - Image Cache - ***********************************************************************/ - -static void cache_image P_ ((struct frame *f, struct image *img)); - - -/* Return a new, initialized image cache that is allocated from the - heap. Call free_image_cache to free an image cache. */ - -struct image_cache * -make_image_cache () -{ - struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c); - int size; - - bzero (c, sizeof *c); - c->size = 50; - c->images = (struct image **) xmalloc (c->size * sizeof *c->images); - size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets; - c->buckets = (struct image **) xmalloc (size); - bzero (c->buckets, size); - return c; -} - - -/* Free image cache of frame F. Be aware that X frames share images - caches. */ - -void -free_image_cache (f) - struct frame *f; -{ - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - if (c) - { - int i; - - /* Cache should not be referenced by any frame when freed. */ - xassert (c->refcount == 0); - - for (i = 0; i < c->used; ++i) - free_image (f, c->images[i]); - xfree (c->images); - xfree (c->buckets); - xfree (c); - FRAME_X_IMAGE_CACHE (f) = NULL; - } -} - - -/* Clear image cache of frame F. FORCE_P non-zero means free all - images. FORCE_P zero means clear only images that haven't been - displayed for some time. Should be called from time to time to - reduce the number of loaded images. If image-eviction-seconds is - non-nil, this frees images in the cache which weren't displayed for - at least that many seconds. */ - -void -clear_image_cache (f, force_p) - struct frame *f; - int force_p; -{ - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - - if (c && INTEGERP (Vimage_cache_eviction_delay)) - { - EMACS_TIME t; - unsigned long old; - int i, any_freed_p = 0; - - EMACS_GET_TIME (t); - old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay); - - for (i = 0; i < c->used; ++i) - { - struct image *img = c->images[i]; - if (img != NULL - && (force_p - || (img->timestamp > old))) - { - free_image (f, img); - any_freed_p = 1; - } - } - - /* We may be clearing the image cache because, for example, - Emacs was iconified for a longer period of time. In that - case, current matrices may still contain references to - images freed above. So, clear these matrices. */ - if (any_freed_p) - { - clear_current_matrices (f); - ++windows_or_buffers_changed; - } - } -} - - -DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache, - 0, 1, 0, - doc: /* Clear the image cache of FRAME. -FRAME nil or omitted means use the selected frame. -FRAME t means clear the image caches of all frames. */) - (frame) - Lisp_Object frame; -{ - if (EQ (frame, Qt)) - { - Lisp_Object tail; - - FOR_EACH_FRAME (tail, frame) - if (FRAME_MAC_P (XFRAME (frame))) - clear_image_cache (XFRAME (frame), 1); - } - else - clear_image_cache (check_x_frame (frame), 1); - - return Qnil; -} - - -/* Return the id of image with Lisp specification SPEC on frame F. - SPEC must be a valid Lisp image specification (see valid_image_p). */ - -int -lookup_image (f, spec) - struct frame *f; - Lisp_Object spec; -{ - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - struct image *img; - int i; - unsigned hash; - struct gcpro gcpro1; - EMACS_TIME now; - - /* F must be a window-system frame, and SPEC must be a valid image - specification. */ - xassert (FRAME_WINDOW_P (f)); - xassert (valid_image_p (spec)); - - GCPRO1 (spec); - - /* Look up SPEC in the hash table of the image cache. */ - hash = sxhash (spec, 0); - i = hash % IMAGE_CACHE_BUCKETS_SIZE; - - for (img = c->buckets[i]; img; img = img->next) - if (img->hash == hash && !NILP (Fequal (img->spec, spec))) - break; - - /* If not found, create a new image and cache it. */ - if (img == NULL) - { - BLOCK_INPUT; - img = make_image (spec, hash); - cache_image (f, img); - img->load_failed_p = img->type->load (f, img) == 0; - xassert (!interrupt_input_blocked); - - /* 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->load_failed_p) - { - Lisp_Object value; - - value = image_spec_value (spec, QCwidth, NULL); - img->width = (INTEGERP (value) - ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH); - value = image_spec_value (spec, QCheight, NULL); - img->height = (INTEGERP (value) - ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT); - } - else - { - /* Handle image type independent image attributes - `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */ - Lisp_Object ascent, margin, relief; - - ascent = image_spec_value (spec, QCascent, NULL); - if (INTEGERP (ascent)) - img->ascent = XFASTINT (ascent); - else if (EQ (ascent, Qcenter)) - img->ascent = CENTERED_IMAGE_ASCENT; - - margin = image_spec_value (spec, QCmargin, NULL); - if (INTEGERP (margin) && XINT (margin) >= 0) - 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->hmargin += abs (img->relief); - img->vmargin += abs (img->relief); - } - } - } - - /* We're using IMG, so set its timestamp to `now'. */ - EMACS_GET_TIME (now); - img->timestamp = EMACS_SECS (now); - - UNGCPRO; - - /* Value is the image id. */ - return img->id; -} - - -/* Cache image IMG in the image cache of frame F. */ - -static void -cache_image (f, img) - struct frame *f; - struct image *img; -{ - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - int i; - - /* Find a free slot in c->images. */ - for (i = 0; i < c->used; ++i) - if (c->images[i] == NULL) - break; - - /* If no free slot found, maybe enlarge c->images. */ - if (i == c->used && c->used == c->size) - { - c->size *= 2; - c->images = (struct image **) xrealloc (c->images, - c->size * sizeof *c->images); - } - - /* Add IMG to c->images, and assign IMG an id. */ - c->images[i] = img; - img->id = i; - if (i == c->used) - ++c->used; - - /* Add IMG to the cache's hash table. */ - i = img->hash % IMAGE_CACHE_BUCKETS_SIZE; - img->next = c->buckets[i]; - if (img->next) - img->next->prev = img; - img->prev = NULL; - c->buckets[i] = img; -} - - -/* Call FN on every image in the image cache of frame F. Used to mark - Lisp Objects in the image cache. */ - -void -forall_images_in_image_cache (f, fn) - struct frame *f; - void (*fn) P_ ((struct image *img)); -{ - if (FRAME_LIVE_P (f) && FRAME_MAC_P (f)) - { - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - if (c) - { - int i; - for (i = 0; i < c->used; ++i) - if (c->images[i]) - fn (c->images[i]); - } - } -} - - - -/*********************************************************************** - Mac support code - ***********************************************************************/ - -#if 0 /* MAC_TODO: Mac specific image code. */ - -static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int, - XImage **, Pixmap *)); -static void x_destroy_x_image P_ ((XImage *)); -static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int)); - - -/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on - frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created. - Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated - via xmalloc. Print error messages via image_error if an error - occurs. Value is non-zero if successful. */ - -static int -x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap) - struct frame *f; - int width, height, depth; - XImage **ximg; - Pixmap *pixmap; -{ -#if 0 /* MAC_TODO: Image support for Mac */ - Display *display = FRAME_W32_DISPLAY (f); - Screen *screen = FRAME_X_SCREEN (f); - Window window = FRAME_W32_WINDOW (f); - - xassert (interrupt_input_blocked); - - if (depth <= 0) - depth = DefaultDepthOfScreen (screen); - *ximg = XCreateImage (display, DefaultVisualOfScreen (screen), - depth, ZPixmap, 0, NULL, width, height, - depth > 16 ? 32 : depth > 8 ? 16 : 8, 0); - if (*ximg == NULL) - { - image_error ("Unable to allocate X image", Qnil, Qnil); - return 0; - } - - /* Allocate image raster. */ - (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height); - - /* Allocate a pixmap of the same size. */ - *pixmap = XCreatePixmap (display, window, width, height, depth); - if (*pixmap == 0) - { - x_destroy_x_image (*ximg); - *ximg = NULL; - image_error ("Unable to create X pixmap", Qnil, Qnil); - return 0; - } -#endif /* MAC_TODO */ - return 1; -} - - -/* Destroy XImage XIMG. Free XIMG->data. */ - -static void -x_destroy_x_image (ximg) - XImage *ximg; -{ - xassert (interrupt_input_blocked); - if (ximg) - { - xfree (ximg->data); - ximg->data = NULL; - XDestroyImage (ximg); - } -} - - -/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT - are width and height of both the image and pixmap. */ - -static void -x_put_x_image (f, ximg, pixmap, width, height) - struct frame *f; - XImage *ximg; - Pixmap pixmap; -{ - GC gc; - - xassert (interrupt_input_blocked); - gc = XCreateGC (NULL, pixmap, 0, NULL); - XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height); - XFreeGC (NULL, gc); -} - -#endif /* MAC_TODO */ - - -/*********************************************************************** - Searching files - ***********************************************************************/ - -static Lisp_Object x_find_image_file P_ ((Lisp_Object)); - -/* Find image file FILE. Look in data-directory, then - x-bitmap-file-path. Value is the full name of the file found, or - nil if not found. */ - -static Lisp_Object -x_find_image_file (file) - Lisp_Object file; -{ - Lisp_Object file_found, search_path; - struct gcpro gcpro1, gcpro2; - int fd; - - file_found = Qnil; - search_path = Fcons (Vdata_directory, Vx_bitmap_file_path); - GCPRO2 (file_found, search_path); - - /* Try to find FILE in data-directory, then x-bitmap-file-path. */ - fd = openp (search_path, file, Qnil, &file_found, Qnil); - - if (fd < 0) - file_found = Qnil; - else - close (fd); - - UNGCPRO; - return file_found; -} - - -/*********************************************************************** - XBM images - ***********************************************************************/ - -static int xbm_load P_ ((struct frame *f, struct image *img)); -static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img, - Lisp_Object file)); -static int xbm_image_p P_ ((Lisp_Object object)); -static int xbm_read_bitmap_file_data P_ ((char *, int *, int *, - unsigned char **)); - - -/* Indices of image specification fields in xbm_format, below. */ - -enum xbm_keyword_index -{ - XBM_TYPE, - XBM_FILE, - XBM_WIDTH, - XBM_HEIGHT, - XBM_DATA, - XBM_FOREGROUND, - XBM_BACKGROUND, - XBM_ASCENT, - XBM_MARGIN, - XBM_RELIEF, - XBM_ALGORITHM, - XBM_HEURISTIC_MASK, - XBM_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid XBM image specifications. */ - -static struct image_keyword xbm_format[XBM_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":file", IMAGE_STRING_VALUE, 0}, - {":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}, - {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 0}, - {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} -}; - -/* Structure describing the image type XBM. */ - -static struct image_type xbm_type = -{ - &Qxbm, - xbm_image_p, - xbm_load, - x_clear_image, - NULL -}; - -/* Tokens returned from xbm_scan. */ - -enum xbm_token -{ - XBM_TK_IDENT = 256, - XBM_TK_NUMBER -}; - - -/* Return non-zero if OBJECT is a valid XBM-type image specification. - A valid specification is a list starting with the symbol `image' - The rest of the list is a property list which must contain an - entry `:type xbm.. - - If the specification specifies a file to load, it must contain - an entry `:file FILENAME' where FILENAME is a string. - - If the specification is for a bitmap loaded from memory it must - contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where - WIDTH and HEIGHT are integers > 0. DATA may be: - - 1. a string large enough to hold the bitmap data, i.e. it must - have a size >= (WIDTH + 7) / 8 * HEIGHT - - 2. a bool-vector of size >= WIDTH * HEIGHT - - 3. a vector of strings or bool-vectors, one for each line of the - bitmap. - - Both the file and data forms may contain the additional entries - `:background COLOR' and `:foreground COLOR'. If not present, - foreground and background of the frame on which the image is - displayed, is used. */ - -static int -xbm_image_p (object) - Lisp_Object object; -{ - struct image_keyword kw[XBM_LAST]; - - bcopy (xbm_format, kw, sizeof kw); - if (!parse_image_spec (object, kw, XBM_LAST, Qxbm)) - return 0; - - xassert (EQ (kw[XBM_TYPE].value, Qxbm)); - - if (kw[XBM_FILE].count) - { - if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count) - return 0; - } - else - { - Lisp_Object data; - int width, height; - - /* Entries for `:width', `:height' and `:data' must be present. */ - if (!kw[XBM_WIDTH].count - || !kw[XBM_HEIGHT].count - || !kw[XBM_DATA].count) - return 0; - - data = kw[XBM_DATA].value; - width = XFASTINT (kw[XBM_WIDTH].value); - height = XFASTINT (kw[XBM_HEIGHT].value); - - /* Check type of data, and width and height against contents of - data. */ - if (VECTORP (data)) - { - int i; - - /* Number of elements of the vector must be >= height. */ - if (XVECTOR (data)->size < height) - return 0; - - /* Each string or bool-vector in data must be large enough - for one line of the image. */ - for (i = 0; i < height; ++i) - { - Lisp_Object elt = XVECTOR (data)->contents[i]; - - if (STRINGP (elt)) - { - if (SCHARS (elt) - < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR) - return 0; - } - else if (BOOL_VECTOR_P (elt)) - { - if (XBOOL_VECTOR (elt)->size < width) - return 0; - } - else - return 0; - } - } - else if (STRINGP (data)) - { - if (SCHARS (data) - < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height) - return 0; - } - else if (BOOL_VECTOR_P (data)) - { - if (XBOOL_VECTOR (data)->size < width * height) - return 0; - } - else - return 0; - } - - /* Baseline must be a value between 0 and 100 (a percentage). */ - if (kw[XBM_ASCENT].count - && XFASTINT (kw[XBM_ASCENT].value) > 100) - return 0; - - return 1; -} - - -/* Scan a bitmap file. FP is the stream to read from. Value is - either an enumerator from enum xbm_token, or a character for a - single-character token, or 0 at end of file. If scanning an - identifier, store the lexeme of the identifier in SVAL. If - scanning a number, store its value in *IVAL. */ - -static int -xbm_scan (fp, sval, ival) - FILE *fp; - char *sval; - int *ival; -{ - int c; - - /* Skip white space. */ - while ((c = fgetc (fp)) != EOF && isspace (c)) - ; - - if (c == EOF) - c = 0; - else if (isdigit (c)) - { - int value = 0, digit; - - if (c == '0') - { - c = fgetc (fp); - if (c == 'x' || c == 'X') - { - while ((c = fgetc (fp)) != EOF) - { - if (isdigit (c)) - digit = c - '0'; - else if (c >= 'a' && c <= 'f') - digit = c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - digit = c - 'A' + 10; - else - break; - value = 16 * value + digit; - } - } - else if (isdigit (c)) - { - value = c - '0'; - while ((c = fgetc (fp)) != EOF - && isdigit (c)) - value = 8 * value + c - '0'; - } - } - else - { - value = c - '0'; - while ((c = fgetc (fp)) != EOF - && isdigit (c)) - value = 10 * value + c - '0'; - } - - if (c != EOF) - ungetc (c, fp); - *ival = value; - c = XBM_TK_NUMBER; - } - else if (isalpha (c) || c == '_') - { - *sval++ = c; - while ((c = fgetc (fp)) != EOF - && (isalnum (c) || c == '_')) - *sval++ = c; - *sval = 0; - if (c != EOF) - ungetc (c, fp); - c = XBM_TK_IDENT; - } - - return c; -} - - -/* Replacement for XReadBitmapFileData which isn't available under old - X versions. FILE is the name of the bitmap file to read. Set - *WIDTH and *HEIGHT to the width and height of the image. Return in - *DATA the bitmap data allocated with xmalloc. Value is non-zero if - successful. */ - -static int -xbm_read_bitmap_file_data (file, width, height, data) - char *file; - int *width, *height; - unsigned char **data; -{ - FILE *fp; - char buffer[BUFSIZ]; - int padding_p = 0; - int v10 = 0; - int bytes_per_line, i, nbytes; - unsigned char *p; - int value; - int LA1; - -#define match() \ - LA1 = xbm_scan (fp, buffer, &value) - -#define expect(TOKEN) \ - if (LA1 != (TOKEN)) \ - goto failure; \ - else \ - match () - -#define expect_ident(IDENT) \ - if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \ - match (); \ - else \ - goto failure - - fp = fopen (file, "r"); - if (fp == NULL) - return 0; - - *width = *height = -1; - *data = NULL; - LA1 = xbm_scan (fp, buffer, &value); - - /* Parse defines for width, height and hot-spots. */ - while (LA1 == '#') - { - match (); - expect_ident ("define"); - expect (XBM_TK_IDENT); - - if (LA1 == XBM_TK_NUMBER); - { - char *p = strrchr (buffer, '_'); - p = p ? p + 1 : buffer; - if (strcmp (p, "width") == 0) - *width = value; - else if (strcmp (p, "height") == 0) - *height = value; - } - expect (XBM_TK_NUMBER); - } - - if (*width < 0 || *height < 0) - goto failure; - - /* Parse bits. Must start with `static'. */ - expect_ident ("static"); - if (LA1 == XBM_TK_IDENT) - { - if (strcmp (buffer, "unsigned") == 0) - { - match (); - expect_ident ("char"); - } - else if (strcmp (buffer, "short") == 0) - { - match (); - v10 = 1; - if (*width % 16 && *width % 16 < 9) - padding_p = 1; - } - else if (strcmp (buffer, "char") == 0) - match (); - else - goto failure; - } - else - goto failure; - - expect (XBM_TK_IDENT); - expect ('['); - expect (']'); - expect ('='); - expect ('{'); - - bytes_per_line = (*width + 7) / 8 + padding_p; - nbytes = bytes_per_line * *height; - p = *data = (char *) xmalloc (nbytes); - - if (v10) - { - - for (i = 0; i < nbytes; i += 2) - { - int val = value; - expect (XBM_TK_NUMBER); - - *p++ = val; - if (!padding_p || ((i + 2) % bytes_per_line)) - *p++ = value >> 8; - - if (LA1 == ',' || LA1 == '}') - match (); - else - goto failure; - } - } - else - { - for (i = 0; i < nbytes; ++i) - { - int val = value; - expect (XBM_TK_NUMBER); - - *p++ = val; - - if (LA1 == ',' || LA1 == '}') - match (); - else - goto failure; - } - } - - fclose (fp); - return 1; - - failure: - - fclose (fp); - if (*data) - { - xfree (*data); - *data = NULL; - } - return 0; - -#undef match -#undef expect -#undef expect_ident -} - - -/* Load XBM image IMG which will be displayed on frame F from file - SPECIFIED_FILE. Value is non-zero if successful. */ - -static int -xbm_load_image_from_file (f, img, specified_file) - struct frame *f; - struct image *img; - Lisp_Object specified_file; -{ - int rc; - unsigned char *data; - int success_p = 0; - Lisp_Object file; - struct gcpro gcpro1; - - xassert (STRINGP (specified_file)); - file = Qnil; - GCPRO1 (file); - - file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNGCPRO; - return 0; - } - - rc = xbm_read_bitmap_file_data (SDATA (file), &img->width, - &img->height, &data); - if (rc) - { - int depth = one_mac_display_info.n_cbits; - unsigned long foreground = FRAME_FOREGROUND_PIXEL (f); - unsigned long background = FRAME_BACKGROUND_PIXEL (f); - Lisp_Object value; - - xassert (img->width > 0 && img->height > 0); - - /* Get foreground and background colors, maybe allocate colors. */ - value = image_spec_value (img->spec, QCforeground, NULL); - if (!NILP (value)) - foreground = x_alloc_image_color (f, img, value, foreground); - - value = image_spec_value (img->spec, QCbackground, NULL); - if (!NILP (value)) - background = x_alloc_image_color (f, img, value, background); - -#if 0 /* MAC_TODO : Port image display to Mac */ - BLOCK_INPUT; - img->pixmap - = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f), - FRAME_W32_WINDOW (f), - data, - img->width, img->height, - foreground, background, - depth); - xfree (data); - - if (img->pixmap == 0) - { - x_clear_image (f, img); - image_error ("Unable to create X pixmap for `%s'", file, Qnil); - } - else - success_p = 1; - - UNBLOCK_INPUT; -#endif /* MAC_TODO */ - } - else - image_error ("Error loading XBM image `%s'", img->spec, Qnil); - - UNGCPRO; - return success_p; -} - - -/* Fill image IMG which is used on frame F with pixmap data. Value is - non-zero if successful. */ - -static int -xbm_load (f, img) - struct frame *f; - struct image *img; -{ - int success_p = 0; - Lisp_Object file_name; - - xassert (xbm_image_p (img->spec)); - - /* If IMG->spec specifies a file name, create a non-file spec from it. */ - file_name = image_spec_value (img->spec, QCfile, NULL); - if (STRINGP (file_name)) - success_p = xbm_load_image_from_file (f, img, file_name); - else - { - struct image_keyword fmt[XBM_LAST]; - Lisp_Object data; - int depth; - unsigned long foreground = FRAME_FOREGROUND_PIXEL (f); - unsigned long background = FRAME_BACKGROUND_PIXEL (f); - char *bits; - int parsed_p; - - /* Parse the list specification. */ - bcopy (xbm_format, fmt, sizeof fmt); - parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm); - xassert (parsed_p); - - /* Get specified width, and height. */ - img->width = XFASTINT (fmt[XBM_WIDTH].value); - img->height = XFASTINT (fmt[XBM_HEIGHT].value); - xassert (img->width > 0 && img->height > 0); - - BLOCK_INPUT; - - if (fmt[XBM_ASCENT].count) - img->ascent = XFASTINT (fmt[XBM_ASCENT].value); - - /* Get foreground and background colors, maybe allocate colors. */ - if (fmt[XBM_FOREGROUND].count) - foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value, - foreground); - if (fmt[XBM_BACKGROUND].count) - background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value, - background); - - /* Set bits to the bitmap image data. */ - data = fmt[XBM_DATA].value; - if (VECTORP (data)) - { - int i; - char *p; - int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR; - - p = bits = (char *) alloca (nbytes * img->height); - for (i = 0; i < img->height; ++i, p += nbytes) - { - Lisp_Object line = XVECTOR (data)->contents[i]; - if (STRINGP (line)) - bcopy (SDATA (line), p, nbytes); - else - bcopy (XBOOL_VECTOR (line)->data, p, nbytes); - } - } - else if (STRINGP (data)) - bits = SDATA (data); - else - bits = XBOOL_VECTOR (data)->data; - -#if 0 /* MAC_TODO : port Mac display code */ - /* Create the pixmap. */ - depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f)); - img->pixmap - = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f), - FRAME_W32_WINDOW (f), - bits, - img->width, img->height, - foreground, background, - depth); -#endif /* MAC_TODO */ - - if (img->pixmap) - success_p = 1; - else - { - image_error ("Unable to create pixmap for XBM image `%s'", - img->spec, Qnil); - x_clear_image (f, img); - } - - UNBLOCK_INPUT; - } - - return success_p; -} - - - -/*********************************************************************** - XPM images - ***********************************************************************/ - -#if HAVE_XPM - -static int xpm_image_p P_ ((Lisp_Object object)); -static int xpm_load P_ ((struct frame *f, struct image *img)); -static int xpm_valid_color_symbols_p P_ ((Lisp_Object)); - -#include "X11/xpm.h" - -/* The symbol `xpm' identifying XPM-format images. */ - -Lisp_Object Qxpm; - -/* Indices of image specification fields in xpm_format, below. */ - -enum xpm_keyword_index -{ - XPM_TYPE, - XPM_FILE, - XPM_DATA, - XPM_ASCENT, - XPM_MARGIN, - XPM_RELIEF, - XPM_ALGORITHM, - XPM_HEURISTIC_MASK, - XPM_COLOR_SYMBOLS, - XPM_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid XPM image specifications. */ - -static struct image_keyword xpm_format[XPM_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":file", IMAGE_STRING_VALUE, 0}, - {":data", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 0}, - {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0} -}; - -/* Structure describing the image type XBM. */ - -static struct image_type xpm_type = -{ - &Qxpm, - xpm_image_p, - xpm_load, - x_clear_image, - NULL -}; - - -/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list - for XPM images. Such a list must consist of conses whose car and - cdr are strings. */ - -static int -xpm_valid_color_symbols_p (color_symbols) - Lisp_Object color_symbols; -{ - while (CONSP (color_symbols)) - { - Lisp_Object sym = XCAR (color_symbols); - if (!CONSP (sym) - || !STRINGP (XCAR (sym)) - || !STRINGP (XCDR (sym))) - break; - color_symbols = XCDR (color_symbols); - } - - return NILP (color_symbols); -} - - -/* Value is non-zero if OBJECT is a valid XPM image specification. */ - -static int -xpm_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[XPM_LAST]; - bcopy (xpm_format, fmt, sizeof fmt); - return (parse_image_spec (object, fmt, XPM_LAST, Qxpm) - /* Either `:file' or `:data' must be present. */ - && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1 - /* Either no `:color-symbols' or it's a list of conses - whose car and cdr are strings. */ - && (fmt[XPM_COLOR_SYMBOLS].count == 0 - || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)) - && (fmt[XPM_ASCENT].count == 0 - || XFASTINT (fmt[XPM_ASCENT].value) < 100)); -} - - -/* Load image IMG which will be displayed on frame F. Value is - non-zero if successful. */ - -static int -xpm_load (f, img) - struct frame *f; - struct image *img; -{ - int rc, i; - XpmAttributes attrs; - Lisp_Object specified_file, color_symbols; - - /* Configure the XPM lib. Use the visual of frame F. Allocate - close colors. Return colors allocated. */ - bzero (&attrs, sizeof attrs); - attrs.visual = FRAME_X_VISUAL (f); - attrs.colormap = FRAME_X_COLORMAP (f); - attrs.valuemask |= XpmVisual; - attrs.valuemask |= XpmColormap; - attrs.valuemask |= XpmReturnAllocPixels; -#ifdef XpmAllocCloseColors - attrs.alloc_close_colors = 1; - attrs.valuemask |= XpmAllocCloseColors; -#else - attrs.closeness = 600; - attrs.valuemask |= XpmCloseness; -#endif - - /* If image specification contains symbolic color definitions, add - these to `attrs'. */ - color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL); - if (CONSP (color_symbols)) - { - Lisp_Object tail; - XpmColorSymbol *xpm_syms; - int i, size; - - attrs.valuemask |= XpmColorSymbols; - - /* Count number of symbols. */ - attrs.numsymbols = 0; - for (tail = color_symbols; CONSP (tail); tail = XCDR (tail)) - ++attrs.numsymbols; - - /* Allocate an XpmColorSymbol array. */ - size = attrs.numsymbols * sizeof *xpm_syms; - xpm_syms = (XpmColorSymbol *) alloca (size); - bzero (xpm_syms, size); - attrs.colorsymbols = xpm_syms; - - /* Fill the color symbol array. */ - for (tail = color_symbols, i = 0; - CONSP (tail); - ++i, tail = XCDR (tail)) - { - Lisp_Object name = XCAR (XCAR (tail)); - Lisp_Object color = XCDR (XCAR (tail)); - xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1); - strcpy (xpm_syms[i].name, SDATA (name)); - xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1); - strcpy (xpm_syms[i].value, SDATA (color)); - } - } - - /* Create a pixmap for the image, either from a file, or from a - string buffer containing data in the same format as an XPM file. */ - BLOCK_INPUT; - specified_file = image_spec_value (img->spec, QCfile, NULL); - if (STRINGP (specified_file)) - { - Lisp_Object file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNBLOCK_INPUT; - return 0; - } - - rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f), - SDATA (file), &img->pixmap, &img->mask, - &attrs); - } - else - { - Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL); - rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f), - SDATA (buffer), - &img->pixmap, &img->mask, - &attrs); - } - UNBLOCK_INPUT; - - if (rc == XpmSuccess) - { - /* Remember allocated colors. */ - img->ncolors = attrs.nalloc_pixels; - img->colors = (unsigned long *) xmalloc (img->ncolors - * sizeof *img->colors); - for (i = 0; i < attrs.nalloc_pixels; ++i) - img->colors[i] = attrs.alloc_pixels[i]; - - img->width = attrs.width; - img->height = attrs.height; - xassert (img->width > 0 && img->height > 0); - - /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */ - BLOCK_INPUT; - XpmFreeAttributes (&attrs); - UNBLOCK_INPUT; - } - else - { - switch (rc) - { - case XpmOpenFailed: - image_error ("Error opening XPM file (%s)", img->spec, Qnil); - break; - - case XpmFileInvalid: - image_error ("Invalid XPM file (%s)", img->spec, Qnil); - break; - - case XpmNoMemory: - image_error ("Out of memory (%s)", img->spec, Qnil); - break; - - case XpmColorFailed: - image_error ("Color allocation error (%s)", img->spec, Qnil); - break; - - default: - image_error ("Unknown error (%s)", img->spec, Qnil); - break; - } - } - - return rc == XpmSuccess; -} - -#endif /* HAVE_XPM != 0 */ - - -#if 0 /* MAC_TODO : Color tables on Mac. */ -/*********************************************************************** - Color table - ***********************************************************************/ - -/* An entry in the color table mapping an RGB color to a pixel color. */ - -struct ct_color -{ - int r, g, b; - unsigned long pixel; - - /* Next in color table collision list. */ - struct ct_color *next; -}; - -/* The bucket vector size to use. Must be prime. */ - -#define CT_SIZE 101 - -/* Value is a hash of the RGB color given by R, G, and B. */ - -#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B)) - -/* The color hash table. */ - -struct ct_color **ct_table; - -/* Number of entries in the color table. */ - -int ct_colors_allocated; - -/* Function prototypes. */ - -static void init_color_table P_ ((void)); -static void free_color_table P_ ((void)); -static unsigned long *colors_in_color_table P_ ((int *n)); -static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b)); -static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p)); - - -/* Initialize the color table. */ - -static void -init_color_table () -{ - int size = CT_SIZE * sizeof (*ct_table); - ct_table = (struct ct_color **) xmalloc (size); - bzero (ct_table, size); - ct_colors_allocated = 0; -} - - -/* Free memory associated with the color table. */ - -static void -free_color_table () -{ - int i; - struct ct_color *p, *next; - - for (i = 0; i < CT_SIZE; ++i) - for (p = ct_table[i]; p; p = next) - { - next = p->next; - xfree (p); - } - - xfree (ct_table); - ct_table = NULL; -} - - -/* Value is a pixel color for RGB color R, G, B on frame F. If an - entry for that color already is in the color table, return the - pixel color of that entry. Otherwise, allocate a new color for R, - G, B, and make an entry in the color table. */ - -static unsigned long -lookup_rgb_color (f, r, g, b) - struct frame *f; - int r, g, b; -{ - unsigned hash = CT_HASH_RGB (r, g, b); - int i = hash % CT_SIZE; - struct ct_color *p; - - for (p = ct_table[i]; p; p = p->next) - if (p->r == r && p->g == g && p->b == b) - break; - - if (p == NULL) - { - COLORREF color; - Colormap cmap; - int rc; - - color = RGB_TO_ULONG (r, g, b); - - ++ct_colors_allocated; - - p = (struct ct_color *) xmalloc (sizeof *p); - p->r = r; - p->g = g; - p->b = b; - p->pixel = color; - p->next = ct_table[i]; - ct_table[i] = p; - } - - return p->pixel; -} - - -/* Look up pixel color PIXEL which is used on frame F in the color - table. If not already present, allocate it. Value is PIXEL. */ - -static unsigned long -lookup_pixel_color (f, pixel) - struct frame *f; - unsigned long pixel; -{ - int i = pixel % CT_SIZE; - struct ct_color *p; - - for (p = ct_table[i]; p; p = p->next) - if (p->pixel == pixel) - break; - - if (p == NULL) - { - XColor color; - Colormap cmap; - int rc; - - BLOCK_INPUT; - - cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); - color.pixel = pixel; - XQueryColor (NULL, cmap, &color); - rc = x_alloc_nearest_color (f, cmap, &color); - UNBLOCK_INPUT; - - if (rc) - { - ++ct_colors_allocated; - - p = (struct ct_color *) xmalloc (sizeof *p); - p->r = color.red; - p->g = color.green; - p->b = color.blue; - p->pixel = pixel; - p->next = ct_table[i]; - ct_table[i] = p; - } - else - return FRAME_FOREGROUND_PIXEL (f); - } - return p->pixel; -} - - -/* Value is a vector of all pixel colors contained in the color table, - allocated via xmalloc. Set *N to the number of colors. */ - -static unsigned long * -colors_in_color_table (n) - int *n; -{ - int i, j; - struct ct_color *p; - unsigned long *colors; - - if (ct_colors_allocated == 0) - { - *n = 0; - colors = NULL; - } - else - { - colors = (unsigned long *) xmalloc (ct_colors_allocated - * sizeof *colors); - *n = ct_colors_allocated; - - for (i = j = 0; i < CT_SIZE; ++i) - for (p = ct_table[i]; p; p = p->next) - colors[j++] = p->pixel; - } - - return colors; -} - -#endif /* MAC_TODO */ - - -/*********************************************************************** - Algorithms - ***********************************************************************/ - -#if 0 /* MAC_TODO : Mac versions of low level algorithms */ -static void x_laplace_write_row P_ ((struct frame *, long *, - int, XImage *, int)); -static void x_laplace_read_row P_ ((struct frame *, Colormap, - XColor *, int, XImage *, int)); - - -/* Fill COLORS with RGB colors from row Y of image XIMG. F is the - frame we operate on, CMAP is the color-map in effect, and WIDTH is - the width of one row in the image. */ - -static void -x_laplace_read_row (f, cmap, colors, width, ximg, y) - struct frame *f; - Colormap cmap; - XColor *colors; - int width; - XImage *ximg; - int y; -{ - int x; - - for (x = 0; x < width; ++x) - colors[x].pixel = XGetPixel (ximg, x, y); - - XQueryColors (NULL, cmap, colors, width); -} - - -/* Write row Y of image XIMG. PIXELS is an array of WIDTH longs - containing the pixel colors to write. F is the frame we are - working on. */ - -static void -x_laplace_write_row (f, pixels, width, ximg, y) - struct frame *f; - long *pixels; - int width; - XImage *ximg; - int y; -{ - int x; - - for (x = 0; x < width; ++x) - XPutPixel (ximg, x, y, pixels[x]); -} -#endif /* MAC_TODO */ - -/* Transform image IMG which is used on frame F with a Laplace - edge-detection algorithm. The result is an image that can be used - to draw disabled buttons, for example. */ - -static void -x_laplace (f, img) - struct frame *f; - struct image *img; -{ -#if 0 /* MAC_TODO : Mac version */ - Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); - XImage *ximg, *oimg; - XColor *in[3]; - long *out; - Pixmap pixmap; - int x, y, i; - long pixel; - int in_y, out_y, rc; - int mv2 = 45000; - - BLOCK_INPUT; - - /* Get the X image IMG->pixmap. */ - ximg = XGetImage (NULL, img->pixmap, - 0, 0, img->width, img->height, ~0, ZPixmap); - - /* Allocate 3 input rows, and one output row of colors. */ - for (i = 0; i < 3; ++i) - in[i] = (XColor *) alloca (img->width * sizeof (XColor)); - out = (long *) alloca (img->width * sizeof (long)); - - /* Create an X image for output. */ - rc = x_create_x_image_and_pixmap (f, img->width, img->height, 0, - &oimg, &pixmap); - - /* Fill first two rows. */ - x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0); - x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1); - in_y = 2; - - /* Write first row, all zeros. */ - init_color_table (); - pixel = lookup_rgb_color (f, 0, 0, 0); - for (x = 0; x < img->width; ++x) - out[x] = pixel; - x_laplace_write_row (f, out, img->width, oimg, 0); - out_y = 1; - - for (y = 2; y < img->height; ++y) - { - int rowa = y % 3; - int rowb = (y + 2) % 3; - - x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++); - - for (x = 0; x < img->width - 2; ++x) - { - int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red; - int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green; - int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue; - - out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff, - b & 0xffff); - } - - x_laplace_write_row (f, out, img->width, oimg, out_y++); - } - - /* Write last line, all zeros. */ - for (x = 0; x < img->width; ++x) - out[x] = pixel; - x_laplace_write_row (f, out, img->width, oimg, out_y); - - /* Free the input image, and free resources of IMG. */ - XDestroyImage (ximg); - x_clear_image (f, img); - - /* Put the output image into pixmap, and destroy it. */ - x_put_x_image (f, oimg, pixmap, img->width, img->height); - x_destroy_x_image (oimg); - - /* Remember new pixmap and colors in IMG. */ - img->pixmap = pixmap; - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); - - UNBLOCK_INPUT; -#endif /* MAC_TODO */ -} - - -/* Build a mask for image IMG which is used on frame F. FILE is the - name of an image file, for error messages. HOW determines how to - determine the background color of IMG. If it is a list '(R G B)', - with R, G, and B being integers >= 0, take that as the color of the - background. Otherwise, determine the background color of IMG - heuristically. Value is non-zero if successful. */ - -static int -x_build_heuristic_mask (f, img, how) - struct frame *f; - struct image *img; - Lisp_Object how; -{ -#if 0 /* MAC_TODO : Mac version */ - Display *dpy = FRAME_W32_DISPLAY (f); - XImage *ximg, *mask_img; - int x, y, rc, look_at_corners_p; - unsigned long bg; - - BLOCK_INPUT; - - /* Create an image and pixmap serving as mask. */ - rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1, - &mask_img, &img->mask); - if (!rc) - { - UNBLOCK_INPUT; - return 0; - } - - /* Get the X image of IMG->pixmap. */ - ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height, - ~0, ZPixmap); - - /* Determine the background color of ximg. If HOW is `(R G B)' - take that as color. Otherwise, try to determine the color - heuristically. */ - look_at_corners_p = 1; - - if (CONSP (how)) - { - int rgb[3], i = 0; - - while (i < 3 - && CONSP (how) - && NATNUMP (XCAR (how))) - { - rgb[i] = XFASTINT (XCAR (how)) & 0xffff; - how = XCDR (how); - } - - if (i == 3 && NILP (how)) - { - char color_name[30]; - XColor exact, color; - Colormap cmap; - - sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]); - - cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); - if (XLookupColor (dpy, cmap, color_name, &exact, &color)) - { - bg = color.pixel; - look_at_corners_p = 0; - } - } - } - - if (look_at_corners_p) - { - unsigned long corners[4]; - int i, best_count; - - /* Get the colors at the corners of ximg. */ - corners[0] = XGetPixel (ximg, 0, 0); - corners[1] = XGetPixel (ximg, img->width - 1, 0); - corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1); - corners[3] = XGetPixel (ximg, 0, img->height - 1); - - /* Choose the most frequently found color as background. */ - for (i = best_count = 0; i < 4; ++i) - { - int j, n; - - for (j = n = 0; j < 4; ++j) - if (corners[i] == corners[j]) - ++n; - - if (n > best_count) - bg = corners[i], best_count = n; - } - } - - /* Set all bits in mask_img to 1 whose color in ximg is different - from the background color bg. */ - for (y = 0; y < img->height; ++y) - for (x = 0; x < img->width; ++x) - XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg); - - /* Put mask_img into img->mask. */ - x_put_x_image (f, mask_img, img->mask, img->width, img->height); - x_destroy_x_image (mask_img); - XDestroyImage (ximg); - - UNBLOCK_INPUT; -#endif /* MAC_TODO */ - - return 1; -} - - - -/*********************************************************************** - PBM (mono, gray, color) - ***********************************************************************/ -#ifdef HAVE_PBM - -static int pbm_image_p P_ ((Lisp_Object object)); -static int pbm_load P_ ((struct frame *f, struct image *img)); -static int pbm_scan_number P_ ((unsigned char **, unsigned char *)); - -/* The symbol `pbm' identifying images of this type. */ - -Lisp_Object Qpbm; - -/* Indices of image specification fields in gs_format, below. */ - -enum pbm_keyword_index -{ - PBM_TYPE, - PBM_FILE, - PBM_DATA, - PBM_ASCENT, - PBM_MARGIN, - PBM_RELIEF, - PBM_ALGORITHM, - PBM_HEURISTIC_MASK, - PBM_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid user-defined image specifications. */ - -static struct image_keyword pbm_format[PBM_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":file", IMAGE_STRING_VALUE, 0}, - {":data", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 0}, - {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} -}; - -/* Structure describing the image type `pbm'. */ - -static struct image_type pbm_type = -{ - &Qpbm, - pbm_image_p, - pbm_load, - x_clear_image, - NULL -}; - - -/* Return non-zero if OBJECT is a valid PBM image specification. */ - -static int -pbm_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[PBM_LAST]; - - bcopy (pbm_format, fmt, sizeof fmt); - - if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm) - || (fmt[PBM_ASCENT].count - && XFASTINT (fmt[PBM_ASCENT].value) > 100)) - return 0; - - /* Must specify either :data or :file. */ - return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1; -} - - -/* Scan a decimal number from *S and return it. Advance *S while - reading the number. END is the end of the string. Value is -1 at - end of input. */ - -static int -pbm_scan_number (s, end) - unsigned char **s, *end; -{ - int c, val = -1; - - while (*s < end) - { - /* Skip white-space. */ - while (*s < end && (c = *(*s)++, isspace (c))) - ; - - if (c == '#') - { - /* Skip comment to end of line. */ - while (*s < end && (c = *(*s)++, c != '\n')) - ; - } - else if (isdigit (c)) - { - /* Read decimal number. */ - val = c - '0'; - while (*s < end && (c = *(*s)++, isdigit (c))) - val = 10 * val + c - '0'; - break; - } - else - break; - } - - return val; -} - - -/* Read FILE into memory. Value is a pointer to a buffer allocated - with xmalloc holding FILE's contents. Value is null if an error - occurred. *SIZE is set to the size of the file. */ - -static char * -pbm_read_file (file, size) - Lisp_Object file; - int *size; -{ - FILE *fp = NULL; - char *buf = NULL; - struct stat st; - - if (stat (SDATA (file), &st) == 0 - && (fp = fopen (SDATA (file), "r")) != NULL - && (buf = (char *) xmalloc (st.st_size), - fread (buf, 1, st.st_size, fp) == st.st_size)) - { - *size = st.st_size; - fclose (fp); - } - else - { - if (fp) - fclose (fp); - if (buf) - { - xfree (buf); - buf = NULL; - } - } - - return buf; -} - - -/* Load PBM image IMG for use on frame F. */ - -static int -pbm_load (f, img) - struct frame *f; - struct image *img; -{ - int raw_p, x, y; - int width, height, max_color_idx = 0; - XImage *ximg; - Lisp_Object file, specified_file; - enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type; - struct gcpro gcpro1; - unsigned char *contents = NULL; - unsigned char *end, *p; - int size; - - specified_file = image_spec_value (img->spec, QCfile, NULL); - file = Qnil; - GCPRO1 (file); - - if (STRINGP (specified_file)) - { - file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNGCPRO; - return 0; - } - - contents = pbm_read_file (file, &size); - if (contents == NULL) - { - image_error ("Error reading `%s'", file, Qnil); - UNGCPRO; - return 0; - } - - p = contents; - end = contents + size; - } - else - { - Lisp_Object data; - data = image_spec_value (img->spec, QCdata, NULL); - p = SDATA (data); - end = p + SBYTES (data); - } - - /* Check magic number. */ - if (end - p < 2 || *p++ != 'P') - { - image_error ("Not a PBM image: `%s'", img->spec, Qnil); - error: - xfree (contents); - UNGCPRO; - return 0; - } - - switch (*p++) - { - case '1': - raw_p = 0, type = PBM_MONO; - break; - - case '2': - raw_p = 0, type = PBM_GRAY; - break; - - case '3': - raw_p = 0, type = PBM_COLOR; - break; - - case '4': - raw_p = 1, type = PBM_MONO; - break; - - case '5': - raw_p = 1, type = PBM_GRAY; - break; - - case '6': - raw_p = 1, type = PBM_COLOR; - break; - - default: - image_error ("Not a PBM image: `%s'", img->spec, Qnil); - goto error; - } - - /* Read width, height, maximum color-component. Characters - starting with `#' up to the end of a line are ignored. */ - width = pbm_scan_number (&p, end); - height = pbm_scan_number (&p, end); - - if (type != PBM_MONO) - { - max_color_idx = pbm_scan_number (&p, end); - if (raw_p && max_color_idx > 255) - max_color_idx = 255; - } - - if (width < 0 - || height < 0 - || (type != PBM_MONO && max_color_idx < 0)) - goto error; - - BLOCK_INPUT; - if (!x_create_x_image_and_pixmap (f, width, height, 0, - &ximg, &img->pixmap)) - { - UNBLOCK_INPUT; - goto error; - } - - /* Initialize the color hash table. */ - init_color_table (); - - if (type == PBM_MONO) - { - int c = 0, g; - - for (y = 0; y < height; ++y) - for (x = 0; x < width; ++x) - { - if (raw_p) - { - if ((x & 7) == 0) - c = *p++; - g = c & 0x80; - c <<= 1; - } - else - g = pbm_scan_number (&p, end); - - XPutPixel (ximg, x, y, (g - ? FRAME_FOREGROUND_PIXEL (f) - : FRAME_BACKGROUND_PIXEL (f))); - } - } - else - { - for (y = 0; y < height; ++y) - for (x = 0; x < width; ++x) - { - int r, g, b; - - if (type == PBM_GRAY) - r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end); - else if (raw_p) - { - r = *p++; - g = *p++; - b = *p++; - } - else - { - r = pbm_scan_number (&p, end); - g = pbm_scan_number (&p, end); - b = pbm_scan_number (&p, end); - } - - if (r < 0 || g < 0 || b < 0) - { - xfree (ximg->data); - ximg->data = NULL; - XDestroyImage (ximg); - UNBLOCK_INPUT; - image_error ("Invalid pixel value in image `%s'", - img->spec, Qnil); - goto error; - } - - /* RGB values are now in the range 0..max_color_idx. - Scale this to the range 0..0xffff supported by X. */ - r = (double) r * 65535 / max_color_idx; - g = (double) g * 65535 / max_color_idx; - b = (double) b * 65535 / max_color_idx; - XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b)); - } - } - - /* Store in IMG->colors the colors allocated for the image, and - free the color table. */ - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); - - /* Put the image into a pixmap. */ - x_put_x_image (f, ximg, img->pixmap, width, height); - x_destroy_x_image (ximg); - UNBLOCK_INPUT; - - img->width = width; - img->height = height; - - UNGCPRO; - xfree (contents); - return 1; -} -#endif /* HAVE_PBM */ - - -/*********************************************************************** - PNG - ***********************************************************************/ - -#if HAVE_PNG - -#include <png.h> - -/* Function prototypes. */ - -static int png_image_p P_ ((Lisp_Object object)); -static int png_load P_ ((struct frame *f, struct image *img)); - -/* The symbol `png' identifying images of this type. */ - -Lisp_Object Qpng; - -/* Indices of image specification fields in png_format, below. */ - -enum png_keyword_index -{ - PNG_TYPE, - PNG_DATA, - PNG_FILE, - PNG_ASCENT, - PNG_MARGIN, - PNG_RELIEF, - PNG_ALGORITHM, - PNG_HEURISTIC_MASK, - PNG_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid user-defined image specifications. */ - -static struct image_keyword png_format[PNG_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":data", IMAGE_STRING_VALUE, 0}, - {":file", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 0}, - {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} -}; - -/* Structure describing the image type `png'. */ - -static struct image_type png_type = -{ - &Qpng, - png_image_p, - png_load, - x_clear_image, - NULL -}; - - -/* Return non-zero if OBJECT is a valid PNG image specification. */ - -static int -png_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[PNG_LAST]; - bcopy (png_format, fmt, sizeof fmt); - - if (!parse_image_spec (object, fmt, PNG_LAST, Qpng) - || (fmt[PNG_ASCENT].count - && XFASTINT (fmt[PNG_ASCENT].value) > 100)) - return 0; - - /* Must specify either the :data or :file keyword. */ - return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1; -} - - -/* Error and warning handlers installed when the PNG library - is initialized. */ - -static void -my_png_error (png_ptr, msg) - png_struct *png_ptr; - char *msg; -{ - xassert (png_ptr != NULL); - image_error ("PNG error: %s", build_string (msg), Qnil); - longjmp (png_ptr->jmpbuf, 1); -} - - -static void -my_png_warning (png_ptr, msg) - png_struct *png_ptr; - char *msg; -{ - xassert (png_ptr != NULL); - image_error ("PNG warning: %s", build_string (msg), Qnil); -} - -/* Memory source for PNG decoding. */ - -struct png_memory_storage -{ - unsigned char *bytes; /* The data */ - size_t len; /* How big is it? */ - int index; /* Where are we? */ -}; - - -/* Function set as reader function when reading PNG image from memory. - PNG_PTR is a pointer to the PNG control structure. Copy LENGTH - bytes from the input to DATA. */ - -static void -png_read_from_memory (png_ptr, data, length) - png_structp png_ptr; - png_bytep data; - png_size_t length; -{ - struct png_memory_storage *tbr - = (struct png_memory_storage *) png_get_io_ptr (png_ptr); - - if (length > tbr->len - tbr->index) - png_error (png_ptr, "Read error"); - - bcopy (tbr->bytes + tbr->index, data, length); - tbr->index = tbr->index + length; -} - -/* Load PNG image IMG for use on frame F. Value is non-zero if - successful. */ - -static int -png_load (f, img) - struct frame *f; - struct image *img; -{ - Lisp_Object file, specified_file; - Lisp_Object specified_data; - int x, y, i; - XImage *ximg, *mask_img = NULL; - struct gcpro gcpro1; - png_struct *png_ptr = NULL; - png_info *info_ptr = NULL, *end_info = NULL; - FILE *fp = NULL; - png_byte sig[8]; - png_byte *pixels = NULL; - png_byte **rows = NULL; - png_uint_32 width, height; - int bit_depth, color_type, interlace_type; - png_byte channels; - png_uint_32 row_bytes; - int transparent_p; - char *gamma_str; - double screen_gamma, image_gamma; - int intent; - struct png_memory_storage tbr; /* Data to be read */ - - /* Find out what file to load. */ - specified_file = image_spec_value (img->spec, QCfile, NULL); - specified_data = image_spec_value (img->spec, QCdata, NULL); - file = Qnil; - GCPRO1 (file); - - if (NILP (specified_data)) - { - file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNGCPRO; - return 0; - } - - /* Open the image file. */ - fp = fopen (SDATA (file), "rb"); - if (!fp) - { - image_error ("Cannot open image file `%s'", file, Qnil); - UNGCPRO; - fclose (fp); - return 0; - } - - /* Check PNG signature. */ - if (fread (sig, 1, sizeof sig, fp) != sizeof sig - || !png_check_sig (sig, sizeof sig)) - { - image_error ("Not a PNG file:` %s'", file, Qnil); - UNGCPRO; - fclose (fp); - return 0; - } - } - else - { - /* Read from memory. */ - tbr.bytes = SDATA (specified_data); - tbr.len = SBYTES (specified_data); - tbr.index = 0; - - /* Check PNG signature. */ - if (tbr.len < sizeof sig - || !png_check_sig (tbr.bytes, sizeof sig)) - { - image_error ("Not a PNG image: `%s'", img->spec, Qnil); - UNGCPRO; - return 0; - } - - /* Need to skip past the signature. */ - tbr.bytes += sizeof (sig); - } - - /* Initialize read and info structs for PNG lib. */ - png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, - my_png_error, my_png_warning); - if (!png_ptr) - { - if (fp) fclose (fp); - UNGCPRO; - return 0; - } - - info_ptr = png_create_info_struct (png_ptr); - if (!info_ptr) - { - png_destroy_read_struct (&png_ptr, NULL, NULL); - if (fp) fclose (fp); - UNGCPRO; - return 0; - } - - end_info = png_create_info_struct (png_ptr); - if (!end_info) - { - png_destroy_read_struct (&png_ptr, &info_ptr, NULL); - if (fp) fclose (fp); - UNGCPRO; - return 0; - } - - /* Set error jump-back. We come back here when the PNG library - detects an error. */ - if (setjmp (png_ptr->jmpbuf)) - { - error: - if (png_ptr) - png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); - xfree (pixels); - xfree (rows); - if (fp) fclose (fp); - UNGCPRO; - return 0; - } - - /* Read image info. */ - if (!NILP (specified_data)) - png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory); - else - png_init_io (png_ptr, fp); - - png_set_sig_bytes (png_ptr, sizeof sig); - png_read_info (png_ptr, info_ptr); - png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, - &interlace_type, NULL, NULL); - - /* If image contains simply transparency data, we prefer to - construct a clipping mask. */ - if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) - transparent_p = 1; - else - transparent_p = 0; - - /* This function is easier to write if we only have to handle - one data format: RGB or RGBA with 8 bits per channel. Let's - transform other formats into that format. */ - - /* Strip more than 8 bits per channel. */ - if (bit_depth == 16) - png_set_strip_16 (png_ptr); - - /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel - if available. */ - png_set_expand (png_ptr); - - /* Convert grayscale images to RGB. */ - if (color_type == PNG_COLOR_TYPE_GRAY - || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb (png_ptr); - - /* The value 2.2 is a guess for PC monitors from PNG example.c. */ - gamma_str = getenv ("SCREEN_GAMMA"); - screen_gamma = gamma_str ? atof (gamma_str) : 2.2; - - /* Tell the PNG lib to handle gamma correction for us. */ - -#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED) - if (png_get_sRGB (png_ptr, info_ptr, &intent)) - /* There is a special chunk in the image specifying the gamma. */ - png_set_sRGB (png_ptr, info_ptr, intent); - else -#endif - if (png_get_gAMA (png_ptr, info_ptr, &image_gamma)) - /* Image contains gamma information. */ - png_set_gamma (png_ptr, screen_gamma, image_gamma); - else - /* Use a default of 0.5 for the image gamma. */ - png_set_gamma (png_ptr, screen_gamma, 0.5); - - /* Handle alpha channel by combining the image with a background - color. Do this only if a real alpha channel is supplied. For - simple transparency, we prefer a clipping mask. */ - if (!transparent_p) - { - png_color_16 *image_background; - - if (png_get_bKGD (png_ptr, info_ptr, &image_background)) - /* Image contains a background color with which to - combine the image. */ - png_set_background (png_ptr, image_background, - PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); - else - { - /* Image does not contain a background color with which - to combine the image data via an alpha channel. Use - the frame's background instead. */ - XColor color; - Colormap cmap; - png_color_16 frame_background; - - BLOCK_INPUT; - cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); - color.pixel = FRAME_BACKGROUND_PIXEL (f); - XQueryColor (FRAME_W32_DISPLAY (f), cmap, &color); - UNBLOCK_INPUT; - - bzero (&frame_background, sizeof frame_background); - frame_background.red = color.red; - frame_background.green = color.green; - frame_background.blue = color.blue; - - png_set_background (png_ptr, &frame_background, - PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); - } - } - - /* Update info structure. */ - png_read_update_info (png_ptr, info_ptr); - - /* Get number of channels. Valid values are 1 for grayscale images - and images with a palette, 2 for grayscale images with transparency - information (alpha channel), 3 for RGB images, and 4 for RGB - images with alpha channel, i.e. RGBA. If conversions above were - sufficient we should only have 3 or 4 channels here. */ - channels = png_get_channels (png_ptr, info_ptr); - xassert (channels == 3 || channels == 4); - - /* Number of bytes needed for one row of the image. */ - row_bytes = png_get_rowbytes (png_ptr, info_ptr); - - /* Allocate memory for the image. */ - pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels); - rows = (png_byte **) xmalloc (height * sizeof *rows); - for (i = 0; i < height; ++i) - rows[i] = pixels + i * row_bytes; - - /* Read the entire image. */ - png_read_image (png_ptr, rows); - png_read_end (png_ptr, info_ptr); - if (fp) - { - fclose (fp); - fp = NULL; - } - - BLOCK_INPUT; - - /* Create the X image and pixmap. */ - if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, - &img->pixmap)) - { - UNBLOCK_INPUT; - goto error; - } - - /* Create an image and pixmap serving as mask if the PNG image - contains an alpha channel. */ - if (channels == 4 - && !transparent_p - && !x_create_x_image_and_pixmap (f, width, height, 1, - &mask_img, &img->mask)) - { - x_destroy_x_image (ximg); - XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap); - img->pixmap = 0; - UNBLOCK_INPUT; - goto error; - } - - /* Fill the X image and mask from PNG data. */ - init_color_table (); - - for (y = 0; y < height; ++y) - { - png_byte *p = rows[y]; - - for (x = 0; x < width; ++x) - { - unsigned r, g, b; - - r = *p++ << 8; - g = *p++ << 8; - b = *p++ << 8; - XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b)); - - /* An alpha channel, aka mask channel, associates variable - transparency with an image. Where other image formats - support binary transparency---fully transparent or fully - opaque---PNG allows up to 254 levels of partial transparency. - The PNG library implements partial transparency by combining - the image with a specified background color. - - I'm not sure how to handle this here nicely: because the - background on which the image is displayed may change, for - real alpha channel support, it would be necessary to create - a new image for each possible background. - - What I'm doing now is that a mask is created if we have - boolean transparency information. Otherwise I'm using - the frame's background color to combine the image with. */ - - if (channels == 4) - { - if (mask_img) - XPutPixel (mask_img, x, y, *p > 0); - ++p; - } - } - } - - /* Remember colors allocated for this image. */ - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); - - /* Clean up. */ - png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); - xfree (rows); - xfree (pixels); - - img->width = width; - img->height = height; - - /* Put the image into the pixmap, then free the X image and its buffer. */ - x_put_x_image (f, ximg, img->pixmap, width, height); - x_destroy_x_image (ximg); - - /* Same for the mask. */ - if (mask_img) - { - x_put_x_image (f, mask_img, img->mask, img->width, img->height); - x_destroy_x_image (mask_img); - } - - UNBLOCK_INPUT; - UNGCPRO; - return 1; -} - -#endif /* HAVE_PNG != 0 */ - - - -/*********************************************************************** - JPEG - ***********************************************************************/ - -#if HAVE_JPEG - -/* Work around a warning about HAVE_STDLIB_H being redefined in - jconfig.h. */ -#ifdef HAVE_STDLIB_H -#define HAVE_STDLIB_H_1 -#undef HAVE_STDLIB_H -#endif /* HAVE_STLIB_H */ - -#include <jpeglib.h> -#include <jerror.h> -#include <setjmp.h> - -#ifdef HAVE_STLIB_H_1 -#define HAVE_STDLIB_H 1 -#endif - -static int jpeg_image_p P_ ((Lisp_Object object)); -static int jpeg_load P_ ((struct frame *f, struct image *img)); - -/* The symbol `jpeg' identifying images of this type. */ - -Lisp_Object Qjpeg; - -/* Indices of image specification fields in gs_format, below. */ - -enum jpeg_keyword_index -{ - JPEG_TYPE, - JPEG_DATA, - JPEG_FILE, - JPEG_ASCENT, - JPEG_MARGIN, - JPEG_RELIEF, - JPEG_ALGORITHM, - JPEG_HEURISTIC_MASK, - JPEG_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid user-defined image specifications. */ - -static struct image_keyword jpeg_format[JPEG_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":data", IMAGE_STRING_VALUE, 0}, - {":file", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 0}, - {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} -}; - -/* Structure describing the image type `jpeg'. */ - -static struct image_type jpeg_type = -{ - &Qjpeg, - jpeg_image_p, - jpeg_load, - x_clear_image, - NULL -}; - - -/* Return non-zero if OBJECT is a valid JPEG image specification. */ - -static int -jpeg_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[JPEG_LAST]; - - bcopy (jpeg_format, fmt, sizeof fmt); - - if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg) - || (fmt[JPEG_ASCENT].count - && XFASTINT (fmt[JPEG_ASCENT].value) > 100)) - return 0; - - /* Must specify either the :data or :file keyword. */ - return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1; -} - - -struct my_jpeg_error_mgr -{ - struct jpeg_error_mgr pub; - jmp_buf setjmp_buffer; -}; - -static void -my_error_exit (cinfo) - j_common_ptr cinfo; -{ - struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err; - longjmp (mgr->setjmp_buffer, 1); -} - -/* Init source method for JPEG data source manager. Called by - jpeg_read_header() before any data is actually read. See - libjpeg.doc from the JPEG lib distribution. */ - -static void -our_init_source (cinfo) - j_decompress_ptr cinfo; -{ -} - - -/* Fill input buffer method for JPEG data source manager. Called - whenever more data is needed. We read the whole image in one step, - so this only adds a fake end of input marker at the end. */ - -static boolean -our_fill_input_buffer (cinfo) - j_decompress_ptr cinfo; -{ - /* Insert a fake EOI marker. */ - struct jpeg_source_mgr *src = cinfo->src; - static JOCTET buffer[2]; - - buffer[0] = (JOCTET) 0xFF; - buffer[1] = (JOCTET) JPEG_EOI; - - src->next_input_byte = buffer; - src->bytes_in_buffer = 2; - return TRUE; -} - - -/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src - is the JPEG data source manager. */ - -static void -our_skip_input_data (cinfo, num_bytes) - j_decompress_ptr cinfo; - long num_bytes; -{ - struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src; - - if (src) - { - if (num_bytes > src->bytes_in_buffer) - ERREXIT (cinfo, JERR_INPUT_EOF); - - src->bytes_in_buffer -= num_bytes; - src->next_input_byte += num_bytes; - } -} - - -/* Method to terminate data source. Called by - jpeg_finish_decompress() after all data has been processed. */ - -static void -our_term_source (cinfo) - j_decompress_ptr cinfo; -{ -} - - -/* Set up the JPEG lib for reading an image from DATA which contains - LEN bytes. CINFO is the decompression info structure created for - reading the image. */ - -static void -jpeg_memory_src (cinfo, data, len) - j_decompress_ptr cinfo; - JOCTET *data; - unsigned int len; -{ - struct jpeg_source_mgr *src; - - if (cinfo->src == NULL) - { - /* First time for this JPEG object? */ - cinfo->src = (struct jpeg_source_mgr *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - sizeof (struct jpeg_source_mgr)); - src = (struct jpeg_source_mgr *) cinfo->src; - src->next_input_byte = data; - } - - src = (struct jpeg_source_mgr *) cinfo->src; - src->init_source = our_init_source; - src->fill_input_buffer = our_fill_input_buffer; - src->skip_input_data = our_skip_input_data; - src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */ - src->term_source = our_term_source; - src->bytes_in_buffer = len; - src->next_input_byte = data; -} - - -/* Load image IMG for use on frame F. Patterned after example.c - from the JPEG lib. */ - -static int -jpeg_load (f, img) - struct frame *f; - struct image *img; -{ - struct jpeg_decompress_struct cinfo; - struct my_jpeg_error_mgr mgr; - Lisp_Object file, specified_file; - Lisp_Object specified_data; - FILE *fp = NULL; - JSAMPARRAY buffer; - int row_stride, x, y; - XImage *ximg = NULL; - int rc; - unsigned long *colors; - int width, height; - struct gcpro gcpro1; - - /* Open the JPEG file. */ - specified_file = image_spec_value (img->spec, QCfile, NULL); - specified_data = image_spec_value (img->spec, QCdata, NULL); - file = Qnil; - GCPRO1 (file); - - if (NILP (specified_data)) - { - file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNGCPRO; - return 0; - } - - fp = fopen (SDATA (file), "r"); - if (fp == NULL) - { - image_error ("Cannot open `%s'", file, Qnil); - UNGCPRO; - return 0; - } - } - - /* Customize libjpeg's error handling to call my_error_exit when an - error is detected. This function will perform a longjmp. */ - mgr.pub.error_exit = my_error_exit; - cinfo.err = jpeg_std_error (&mgr.pub); - - if ((rc = setjmp (mgr.setjmp_buffer)) != 0) - { - if (rc == 1) - { - /* Called from my_error_exit. Display a JPEG error. */ - char buffer[JMSG_LENGTH_MAX]; - cinfo.err->format_message ((j_common_ptr) &cinfo, buffer); - image_error ("Error reading JPEG image `%s': %s", img->spec, - build_string (buffer)); - } - - /* Close the input file and destroy the JPEG object. */ - if (fp) - fclose (fp); - jpeg_destroy_decompress (&cinfo); - - BLOCK_INPUT; - - /* If we already have an XImage, free that. */ - x_destroy_x_image (ximg); - - /* Free pixmap and colors. */ - x_clear_image (f, img); - - UNBLOCK_INPUT; - UNGCPRO; - return 0; - } - - /* Create the JPEG decompression object. Let it read from fp. - Read the JPEG image header. */ - jpeg_create_decompress (&cinfo); - - if (NILP (specified_data)) - jpeg_stdio_src (&cinfo, fp); - else - jpeg_memory_src (&cinfo, SDATA (specified_data), - SBYTES (specified_data)); - - jpeg_read_header (&cinfo, TRUE); - - /* Customize decompression so that color quantization will be used. - Start decompression. */ - cinfo.quantize_colors = TRUE; - jpeg_start_decompress (&cinfo); - width = img->width = cinfo.output_width; - height = img->height = cinfo.output_height; - - BLOCK_INPUT; - - /* Create X image and pixmap. */ - if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, - &img->pixmap)) - { - UNBLOCK_INPUT; - longjmp (mgr.setjmp_buffer, 2); - } - - /* Allocate colors. When color quantization is used, - cinfo.actual_number_of_colors has been set with the number of - colors generated, and cinfo.colormap is a two-dimensional array - of color indices in the range 0..cinfo.actual_number_of_colors. - No more than 255 colors will be generated. */ - { - int i, ir, ig, ib; - - if (cinfo.out_color_components > 2) - ir = 0, ig = 1, ib = 2; - else if (cinfo.out_color_components > 1) - ir = 0, ig = 1, ib = 0; - else - ir = 0, ig = 0, ib = 0; - - /* Use the color table mechanism because it handles colors that - cannot be allocated nicely. Such colors will be replaced with - a default color, and we don't have to care about which colors - can be freed safely, and which can't. */ - init_color_table (); - colors = (unsigned long *) alloca (cinfo.actual_number_of_colors - * sizeof *colors); - - for (i = 0; i < cinfo.actual_number_of_colors; ++i) - { - /* Multiply RGB values with 255 because X expects RGB values - in the range 0..0xffff. */ - int r = cinfo.colormap[ir][i] << 8; - int g = cinfo.colormap[ig][i] << 8; - int b = cinfo.colormap[ib][i] << 8; - colors[i] = lookup_rgb_color (f, r, g, b); - } - - /* Remember those colors actually allocated. */ - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); - } - - /* Read pixels. */ - row_stride = width * cinfo.output_components; - buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE, - row_stride, 1); - for (y = 0; y < height; ++y) - { - jpeg_read_scanlines (&cinfo, buffer, 1); - for (x = 0; x < cinfo.output_width; ++x) - XPutPixel (ximg, x, y, colors[buffer[0][x]]); - } - - /* Clean up. */ - jpeg_finish_decompress (&cinfo); - jpeg_destroy_decompress (&cinfo); - if (fp) - fclose (fp); - - /* Put the image into the pixmap. */ - x_put_x_image (f, ximg, img->pixmap, width, height); - x_destroy_x_image (ximg); - UNBLOCK_INPUT; - UNGCPRO; - return 1; -} - -#endif /* HAVE_JPEG */ - - - -/*********************************************************************** - TIFF - ***********************************************************************/ - -#if HAVE_TIFF - -#include <tiffio.h> - -static int tiff_image_p P_ ((Lisp_Object object)); -static int tiff_load P_ ((struct frame *f, struct image *img)); - -/* The symbol `tiff' identifying images of this type. */ - -Lisp_Object Qtiff; - -/* Indices of image specification fields in tiff_format, below. */ - -enum tiff_keyword_index -{ - TIFF_TYPE, - TIFF_DATA, - TIFF_FILE, - TIFF_ASCENT, - TIFF_MARGIN, - TIFF_RELIEF, - TIFF_ALGORITHM, - TIFF_HEURISTIC_MASK, - TIFF_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid user-defined image specifications. */ - -static struct image_keyword tiff_format[TIFF_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":data", IMAGE_STRING_VALUE, 0}, - {":file", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 0}, - {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} -}; - -/* Structure describing the image type `tiff'. */ - -static struct image_type tiff_type = -{ - &Qtiff, - tiff_image_p, - tiff_load, - x_clear_image, - NULL -}; - - -/* Return non-zero if OBJECT is a valid TIFF image specification. */ - -static int -tiff_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[TIFF_LAST]; - bcopy (tiff_format, fmt, sizeof fmt); - - if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff) - || (fmt[TIFF_ASCENT].count - && XFASTINT (fmt[TIFF_ASCENT].value) > 100)) - return 0; - - /* Must specify either the :data or :file keyword. */ - return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1; -} - - -/* Reading from a memory buffer for TIFF images Based on the PNG - memory source, but we have to provide a lot of extra functions. - Blah. - - We really only need to implement read and seek, but I am not - convinced that the TIFF library is smart enough not to destroy - itself if we only hand it the function pointers we need to - override. */ - -typedef struct -{ - unsigned char *bytes; - size_t len; - int index; -} -tiff_memory_source; - -static size_t -tiff_read_from_memory (data, buf, size) - thandle_t data; - tdata_t buf; - tsize_t size; -{ - tiff_memory_source *src = (tiff_memory_source *) data; - - if (size > src->len - src->index) - return (size_t) -1; - bcopy (src->bytes + src->index, buf, size); - src->index += size; - return size; -} - -static size_t -tiff_write_from_memory (data, buf, size) - thandle_t data; - tdata_t buf; - tsize_t size; -{ - return (size_t) -1; -} - -static toff_t -tiff_seek_in_memory (data, off, whence) - thandle_t data; - toff_t off; - int whence; -{ - tiff_memory_source *src = (tiff_memory_source *) data; - int idx; - - switch (whence) - { - case SEEK_SET: /* Go from beginning of source. */ - idx = off; - break; - - case SEEK_END: /* Go from end of source. */ - idx = src->len + off; - break; - - case SEEK_CUR: /* Go from current position. */ - idx = src->index + off; - break; - - default: /* Invalid `whence'. */ - return -1; - } - - if (idx > src->len || idx < 0) - return -1; - - src->index = idx; - return src->index; -} - -static int -tiff_close_memory (data) - thandle_t data; -{ - /* NOOP */ - return 0; -} - -static int -tiff_mmap_memory (data, pbase, psize) - thandle_t data; - tdata_t *pbase; - toff_t *psize; -{ - /* It is already _IN_ memory. */ - return 0; -} - -static void -tiff_unmap_memory (data, base, size) - thandle_t data; - tdata_t base; - toff_t size; -{ - /* We don't need to do this. */ -} - -static toff_t -tiff_size_of_memory (data) - thandle_t data; -{ - return ((tiff_memory_source *) data)->len; -} - -/* Load TIFF image IMG for use on frame F. Value is non-zero if - successful. */ - -static int -tiff_load (f, img) - struct frame *f; - struct image *img; -{ - Lisp_Object file, specified_file; - Lisp_Object specified_data; - TIFF *tiff; - int width, height, x, y; - uint32 *buf; - int rc; - XImage *ximg; - struct gcpro gcpro1; - tiff_memory_source memsrc; - - specified_file = image_spec_value (img->spec, QCfile, NULL); - specified_data = image_spec_value (img->spec, QCdata, NULL); - file = Qnil; - GCPRO1 (file); - - if (NILP (specified_data)) - { - /* Read from a file */ - file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", file, Qnil); - UNGCPRO; - return 0; - } - - /* Try to open the image file. */ - tiff = TIFFOpen (SDATA (file), "r"); - if (tiff == NULL) - { - image_error ("Cannot open `%s'", file, Qnil); - UNGCPRO; - return 0; - } - } - else - { - /* Memory source! */ - memsrc.bytes = SDATA (specified_data); - memsrc.len = SBYTES (specified_data); - memsrc.index = 0; - - tiff = TIFFClientOpen ("memory_source", "r", &memsrc, - (TIFFReadWriteProc) tiff_read_from_memory, - (TIFFReadWriteProc) tiff_write_from_memory, - tiff_seek_in_memory, - tiff_close_memory, - tiff_size_of_memory, - tiff_mmap_memory, - tiff_unmap_memory); - - if (!tiff) - { - image_error ("Cannot open memory source for `%s'", img->spec, Qnil); - UNGCPRO; - return 0; - } - } - - /* Get width and height of the image, and allocate a raster buffer - of width x height 32-bit values. */ - TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width); - TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height); - buf = (uint32 *) xmalloc (width * height * sizeof *buf); - - rc = TIFFReadRGBAImage (tiff, width, height, buf, 0); - TIFFClose (tiff); - if (!rc) - { - image_error ("Error reading TIFF image `%s'", img->spec, Qnil); - xfree (buf); - UNGCPRO; - return 0; - } - - BLOCK_INPUT; - - /* Create the X image and pixmap. */ - if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) - { - UNBLOCK_INPUT; - xfree (buf); - UNGCPRO; - return 0; - } - - /* Initialize the color table. */ - init_color_table (); - - /* Process the pixel raster. Origin is in the lower-left corner. */ - for (y = 0; y < height; ++y) - { - uint32 *row = buf + y * width; - - for (x = 0; x < width; ++x) - { - uint32 abgr = row[x]; - int r = TIFFGetR (abgr) << 8; - int g = TIFFGetG (abgr) << 8; - int b = TIFFGetB (abgr) << 8; - XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b)); - } - } - - /* Remember the colors allocated for the image. Free the color table. */ - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); - - /* Put the image into the pixmap, then free the X image and its buffer. */ - x_put_x_image (f, ximg, img->pixmap, width, height); - x_destroy_x_image (ximg); - xfree (buf); - UNBLOCK_INPUT; - - img->width = width; - img->height = height; - - UNGCPRO; - return 1; -} - -#endif /* HAVE_TIFF != 0 */ - - - -/*********************************************************************** - GIF - ***********************************************************************/ - -#if HAVE_GIF - -#include <gif_lib.h> - -static int gif_image_p P_ ((Lisp_Object object)); -static int gif_load P_ ((struct frame *f, struct image *img)); - -/* The symbol `gif' identifying images of this type. */ - -Lisp_Object Qgif; - -/* Indices of image specification fields in gif_format, below. */ - -enum gif_keyword_index -{ - GIF_TYPE, - GIF_DATA, - GIF_FILE, - GIF_ASCENT, - GIF_MARGIN, - GIF_RELIEF, - GIF_ALGORITHM, - GIF_HEURISTIC_MASK, - GIF_IMAGE, - GIF_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid user-defined image specifications. */ - -static struct image_keyword gif_format[GIF_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":data", IMAGE_STRING_VALUE, 0}, - {":file", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 0}, - {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0} -}; - -/* Structure describing the image type `gif'. */ - -static struct image_type gif_type = -{ - &Qgif, - gif_image_p, - gif_load, - x_clear_image, - NULL -}; - -/* Return non-zero if OBJECT is a valid GIF image specification. */ - -static int -gif_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[GIF_LAST]; - bcopy (gif_format, fmt, sizeof fmt); - - if (!parse_image_spec (object, fmt, GIF_LAST, Qgif) - || (fmt[GIF_ASCENT].count - && XFASTINT (fmt[GIF_ASCENT].value) > 100)) - return 0; - - /* Must specify either the :data or :file keyword. */ - return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1; -} - -/* Reading a GIF image from memory - Based on the PNG memory stuff to a certain extent. */ - -typedef struct -{ - unsigned char *bytes; - size_t len; - int index; -} -gif_memory_source; - -/* Make the current memory source available to gif_read_from_memory. - It's done this way because not all versions of libungif support - a UserData field in the GifFileType structure. */ -static gif_memory_source *current_gif_memory_src; - -static int -gif_read_from_memory (file, buf, len) - GifFileType *file; - GifByteType *buf; - int len; -{ - gif_memory_source *src = current_gif_memory_src; - - if (len > src->len - src->index) - return -1; - - bcopy (src->bytes + src->index, buf, len); - src->index += len; - return len; -} - - -/* Load GIF image IMG for use on frame F. Value is non-zero if - successful. */ - -static int -gif_load (f, img) - struct frame *f; - struct image *img; -{ - Lisp_Object file, specified_file; - Lisp_Object specified_data; - int rc, width, height, x, y, i; - XImage *ximg; - ColorMapObject *gif_color_map; - unsigned long pixel_colors[256]; - GifFileType *gif; - struct gcpro gcpro1; - Lisp_Object image; - int ino, image_left, image_top, image_width, image_height; - gif_memory_source memsrc; - unsigned char *raster; - - specified_file = image_spec_value (img->spec, QCfile, NULL); - specified_data = image_spec_value (img->spec, QCdata, NULL); - file = Qnil; - GCPRO1 (file); - - if (NILP (specified_data)) - { - file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNGCPRO; - return 0; - } - - /* Open the GIF file. */ - gif = DGifOpenFileName (SDATA (file)); - if (gif == NULL) - { - image_error ("Cannot open `%s'", file, Qnil); - UNGCPRO; - return 0; - } - } - else - { - /* Read from memory! */ - current_gif_memory_src = &memsrc; - memsrc.bytes = SDATA (specified_data); - memsrc.len = SBYTES (specified_data); - memsrc.index = 0; - - gif = DGifOpen(&memsrc, gif_read_from_memory); - if (!gif) - { - image_error ("Cannot open memory source `%s'", img->spec, Qnil); - UNGCPRO; - return 0; - } - } - - /* Read entire contents. */ - rc = DGifSlurp (gif); - if (rc == GIF_ERROR) - { - image_error ("Error reading `%s'", img->spec, Qnil); - DGifCloseFile (gif); - UNGCPRO; - return 0; - } - - image = image_spec_value (img->spec, QCindex, NULL); - ino = INTEGERP (image) ? XFASTINT (image) : 0; - if (ino >= gif->ImageCount) - { - image_error ("Invalid image number `%s' in image `%s'", - image, img->spec); - DGifCloseFile (gif); - UNGCPRO; - return 0; - } - - width = img->width = gif->SWidth; - height = img->height = gif->SHeight; - - BLOCK_INPUT; - - /* Create the X image and pixmap. */ - if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) - { - UNBLOCK_INPUT; - DGifCloseFile (gif); - UNGCPRO; - return 0; - } - - /* Allocate colors. */ - gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap; - if (!gif_color_map) - gif_color_map = gif->SColorMap; - init_color_table (); - bzero (pixel_colors, sizeof pixel_colors); - - for (i = 0; i < gif_color_map->ColorCount; ++i) - { - int r = gif_color_map->Colors[i].Red << 8; - int g = gif_color_map->Colors[i].Green << 8; - int b = gif_color_map->Colors[i].Blue << 8; - pixel_colors[i] = lookup_rgb_color (f, r, g, b); - } - - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); - - /* Clear the part of the screen image that are not covered by - the image from the GIF file. Full animated GIF support - requires more than can be done here (see the gif89 spec, - disposal methods). Let's simply assume that the part - not covered by a sub-image is in the frame's background color. */ - image_top = gif->SavedImages[ino].ImageDesc.Top; - image_left = gif->SavedImages[ino].ImageDesc.Left; - image_width = gif->SavedImages[ino].ImageDesc.Width; - image_height = gif->SavedImages[ino].ImageDesc.Height; - - for (y = 0; y < image_top; ++y) - for (x = 0; x < width; ++x) - XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); - - for (y = image_top + image_height; y < height; ++y) - for (x = 0; x < width; ++x) - XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); - - for (y = image_top; y < image_top + image_height; ++y) - { - for (x = 0; x < image_left; ++x) - XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); - for (x = image_left + image_width; x < width; ++x) - XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); - } - - /* Read the GIF image into the X image. We use a local variable - `raster' here because RasterBits below is a char *, and invites - problems with bytes >= 0x80. */ - raster = (unsigned char *) gif->SavedImages[ino].RasterBits; - - if (gif->SavedImages[ino].ImageDesc.Interlace) - { - static int interlace_start[] = {0, 4, 2, 1}; - static int interlace_increment[] = {8, 8, 4, 2}; - int pass, inc; - int row = interlace_start[0]; - - pass = 0; - - for (y = 0; y < image_height; y++) - { - if (row >= image_height) - { - row = interlace_start[++pass]; - while (row >= image_height) - row = interlace_start[++pass]; - } - - for (x = 0; x < image_width; x++) - { - int i = raster[(y * image_width) + x]; - XPutPixel (ximg, x + image_left, row + image_top, - pixel_colors[i]); - } - - row += interlace_increment[pass]; - } - } - else - { - for (y = 0; y < image_height; ++y) - for (x = 0; x < image_width; ++x) - { - int i = raster[y* image_width + x]; - XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]); - } - } - - DGifCloseFile (gif); - - /* Put the image into the pixmap, then free the X image and its buffer. */ - x_put_x_image (f, ximg, img->pixmap, width, height); - x_destroy_x_image (ximg); - UNBLOCK_INPUT; - - UNGCPRO; - return 1; -} - -#endif /* HAVE_GIF != 0 */ - - - -/*********************************************************************** - Ghostscript - ***********************************************************************/ - -#ifdef HAVE_GHOSTSCRIPT -static int gs_image_p P_ ((Lisp_Object object)); -static int gs_load P_ ((struct frame *f, struct image *img)); -static void gs_clear_image P_ ((struct frame *f, struct image *img)); - -/* The symbol `postscript' identifying images of this type. */ - -Lisp_Object Qpostscript; - -/* Keyword symbols. */ - -Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height; - -/* Indices of image specification fields in gs_format, below. */ - -enum gs_keyword_index -{ - GS_TYPE, - GS_PT_WIDTH, - GS_PT_HEIGHT, - GS_FILE, - GS_LOADER, - GS_BOUNDING_BOX, - GS_ASCENT, - GS_MARGIN, - GS_RELIEF, - GS_ALGORITHM, - GS_HEURISTIC_MASK, - GS_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid user-defined image specifications. */ - -static struct image_keyword gs_format[GS_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1}, - {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1}, - {":file", IMAGE_STRING_VALUE, 1}, - {":loader", IMAGE_FUNCTION_VALUE, 0}, - {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1}, - {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 0}, - {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} -}; - -/* Structure describing the image type `ghostscript'. */ - -static struct image_type gs_type = -{ - &Qpostscript, - gs_image_p, - gs_load, - gs_clear_image, - NULL -}; - - -/* Free X resources of Ghostscript image IMG which is used on frame F. */ - -static void -gs_clear_image (f, img) - struct frame *f; - struct image *img; -{ - /* IMG->data.ptr_val may contain a recorded colormap. */ - xfree (img->data.ptr_val); - x_clear_image (f, img); -} - - -/* Return non-zero if OBJECT is a valid Ghostscript image - specification. */ - -static int -gs_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[GS_LAST]; - Lisp_Object tem; - int i; - - bcopy (gs_format, fmt, sizeof fmt); - - if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript) - || (fmt[GS_ASCENT].count - && XFASTINT (fmt[GS_ASCENT].value) > 100)) - return 0; - - /* Bounding box must be a list or vector containing 4 integers. */ - tem = fmt[GS_BOUNDING_BOX].value; - if (CONSP (tem)) - { - for (i = 0; i < 4; ++i, tem = XCDR (tem)) - if (!CONSP (tem) || !INTEGERP (XCAR (tem))) - return 0; - if (!NILP (tem)) - return 0; - } - else if (VECTORP (tem)) - { - if (XVECTOR (tem)->size != 4) - return 0; - for (i = 0; i < 4; ++i) - if (!INTEGERP (XVECTOR (tem)->contents[i])) - return 0; - } - else - return 0; - - return 1; -} - - -/* Load Ghostscript image IMG for use on frame F. Value is non-zero - if successful. */ - -static int -gs_load (f, img) - struct frame *f; - struct image *img; -{ - char buffer[100]; - Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width; - struct gcpro gcpro1, gcpro2; - Lisp_Object frame; - double in_width, in_height; - Lisp_Object pixel_colors = Qnil; - - /* Compute pixel size of pixmap needed from the given size in the - image specification. Sizes in the specification are in pt. 1 pt - = 1/72 in, xdpi and ydpi are stored in the frame's X display - info. */ - pt_width = image_spec_value (img->spec, QCpt_width, NULL); - in_width = XFASTINT (pt_width) / 72.0; - img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx; - pt_height = image_spec_value (img->spec, QCpt_height, NULL); - in_height = XFASTINT (pt_height) / 72.0; - img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy; - - /* Create the pixmap. */ - BLOCK_INPUT; - xassert (img->pixmap == 0); - img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), - img->width, img->height, - DefaultDepthOfScreen (FRAME_X_SCREEN (f))); - UNBLOCK_INPUT; - - if (!img->pixmap) - { - image_error ("Unable to create pixmap for `%s'", img->spec, Qnil); - return 0; - } - - /* Call the loader to fill the pixmap. It returns a process object - if successful. We do not record_unwind_protect here because - other places in redisplay like calling window scroll functions - don't either. Let the Lisp loader use `unwind-protect' instead. */ - GCPRO2 (window_and_pixmap_id, pixel_colors); - - sprintf (buffer, "%lu %lu", - (unsigned long) FRAME_W32_WINDOW (f), - (unsigned long) img->pixmap); - window_and_pixmap_id = build_string (buffer); - - sprintf (buffer, "%lu %lu", - FRAME_FOREGROUND_PIXEL (f), - FRAME_BACKGROUND_PIXEL (f)); - pixel_colors = build_string (buffer); - - XSETFRAME (frame, f); - loader = image_spec_value (img->spec, QCloader, NULL); - if (NILP (loader)) - loader = intern ("gs-load-image"); - - img->data.lisp_val = call6 (loader, frame, img->spec, - make_number (img->width), - make_number (img->height), - window_and_pixmap_id, - pixel_colors); - UNGCPRO; - return PROCESSP (img->data.lisp_val); -} - - -/* Kill the Ghostscript process that was started to fill PIXMAP on - frame F. Called from XTread_socket when receiving an event - telling Emacs that Ghostscript has finished drawing. */ - -void -x_kill_gs_process (pixmap, f) - Pixmap pixmap; - struct frame *f; -{ - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - int class, i; - struct image *img; - - /* Find the image containing PIXMAP. */ - for (i = 0; i < c->used; ++i) - if (c->images[i]->pixmap == pixmap) - break; - - /* Kill the GS process. We should have found PIXMAP in the image - cache and its image should contain a process object. */ - xassert (i < c->used); - img = c->images[i]; - xassert (PROCESSP (img->data.lisp_val)); - Fkill_process (img->data.lisp_val, Qnil); - img->data.lisp_val = Qnil; - - /* On displays with a mutable colormap, figure out the colors - allocated for the image by looking at the pixels of an XImage for - img->pixmap. */ - class = FRAME_W32_DISPLAY_INFO (f)->visual->class; - if (class != StaticColor && class != StaticGray && class != TrueColor) - { - XImage *ximg; - - BLOCK_INPUT; - - /* Try to get an XImage for img->pixmep. */ - ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap, - 0, 0, img->width, img->height, ~0, ZPixmap); - if (ximg) - { - int x, y; - - /* Initialize the color table. */ - init_color_table (); - - /* For each pixel of the image, look its color up in the - color table. After having done so, the color table will - contain an entry for each color used by the image. */ - for (y = 0; y < img->height; ++y) - for (x = 0; x < img->width; ++x) - { - unsigned long pixel = XGetPixel (ximg, x, y); - lookup_pixel_color (f, pixel); - } - - /* Record colors in the image. Free color table and XImage. */ - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); - XDestroyImage (ximg); - -#if 0 /* This doesn't seem to be the case. If we free the colors - here, we get a BadAccess later in x_clear_image when - freeing the colors. */ - /* We have allocated colors once, but Ghostscript has also - allocated colors on behalf of us. So, to get the - reference counts right, free them once. */ - if (img->ncolors) - { - Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); - XFreeColors (FRAME_W32_DISPLAY (f), cmap, - img->colors, img->ncolors, 0); - } -#endif - } - else - image_error ("Cannot get X image of `%s'; colors will not be freed", - img->spec, Qnil); - - UNBLOCK_INPUT; - } -} - -#endif /* HAVE_GHOSTSCRIPT */ - - -/*********************************************************************** Window properties ***********************************************************************/ DEFUN ("x-change-window-property", Fx_change_window_property, - Sx_change_window_property, 2, 3, 0, + Sx_change_window_property, 2, 6, 0, doc: /* Change window property PROP to VALUE on the X window of FRAME. -PROP and VALUE must be strings. FRAME nil or omitted means use the -selected frame. Value is VALUE. */) - (prop, value, frame) - Lisp_Object frame, prop, value; +VALUE may be a string or a list of conses, numbers and/or strings. +If an element in the list is a string, it is converted to +an Atom and the value of the Atom is used. If an element is a cons, +it is converted to a 32 bit number where the car is the 16 top bits and the +cdr is the lower 16 bits. +FRAME nil or omitted means use the selected frame. +If TYPE is given and non-nil, it is the name of the type of VALUE. +If TYPE is not given or nil, the type is STRING. +FORMAT gives the size in bits of each element if VALUE is a list. +It must be one of 8, 16 or 32. +If VALUE is a string or FORMAT is nil or not given, FORMAT defaults to 8. +If OUTER_P is non-nil, the property is changed for the outer X window of +FRAME. Default is to change on the edit X window. + +Value is VALUE. */) + (prop, value, frame, type, format, outer_p) + Lisp_Object prop, value, frame, type, format, outer_p; { #if 0 /* MAC_TODO : port window properties to Mac */ struct frame *f = check_x_frame (frame); @@ -8686,38 +4195,6 @@ selection dialog's entry field, if MUSTMATCH is non-nil. */) /*********************************************************************** - Tests - ***********************************************************************/ - -#if GLYPH_DEBUG - -DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0, - doc: /* Value is non-nil if SPEC is a valid image specification. */) - (spec) - Lisp_Object spec; -{ - return valid_image_p (spec) ? Qt : Qnil; -} - - -DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "") - (spec) - Lisp_Object spec; -{ - int id = -1; - - if (valid_image_p (spec)) - id = lookup_image (SELECTED_FRAME (), spec); - - debug_print (spec); - return make_number (id); -} - -#endif /* GLYPH_DEBUG != 0 */ - - - -/*********************************************************************** Initialization ***********************************************************************/ @@ -8772,8 +4249,6 @@ syms_of_macfns () staticpro (&Qsuppress_icon); Qundefined_color = intern ("undefined-color"); staticpro (&Qundefined_color); - Qcenter = intern ("center"); - staticpro (&Qcenter); /* This is the end of symbol initialization. */ Qhyper = intern ("hyper"); @@ -8795,10 +4270,6 @@ syms_of_macfns () Vtext_property_default_nonsticky = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky); - - Qlaplace = intern ("laplace"); - staticpro (&Qlaplace); - Qface_set_after_frame_default = intern ("face-set-after-frame-default"); staticpro (&Qface_set_after_frame_default); @@ -8807,10 +4278,6 @@ syms_of_macfns () Fput (Qundefined_color, Qerror_message, build_string ("Undefined color")); - DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path, - doc: /* List of directories to search for window system bitmap files. */); - Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH"); - DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape, doc: /* The shape of the pointer when over text. Changing the value does not affect existing frames @@ -8865,16 +4332,11 @@ such a font. This is especially effective for such large fonts as Chinese, Japanese, and Korean. */); Vx_pixel_size_width_font_regexp = Qnil; - DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay, - doc: /* Time after which cached images are removed from the cache. -When an image has not been displayed this many seconds, remove it -from the image cache. Value must be an integer or nil with nil -meaning don't clear the cache. */); - Vimage_cache_eviction_delay = make_number (30 * 60); - + /* X window properties. */ defsubr (&Sx_change_window_property); defsubr (&Sx_delete_window_property); defsubr (&Sx_window_property); + defsubr (&Sxw_display_color_p); defsubr (&Sx_display_grayscale_p); defsubr (&Sxw_color_defined_p); @@ -8911,118 +4373,23 @@ meaning don't clear the cache. */); load_font_func = x_load_font; find_ccl_program_func = x_find_ccl_program; query_font_func = x_query_font; - set_frame_fontset_func = x_set_font; check_window_system_func = check_mac; -#if 0 /* MAC_TODO: Image support for Mac Images. */ - Qxbm = intern ("xbm"); - staticpro (&Qxbm); - QCtype = intern (":type"); - staticpro (&QCtype); - QCconversion = intern (":conversion"); - staticpro (&QCconversion); - QCheuristic_mask = intern (":heuristic-mask"); - staticpro (&QCheuristic_mask); - QCcolor_symbols = intern (":color-symbols"); - staticpro (&QCcolor_symbols); - QCascent = intern (":ascent"); - staticpro (&QCascent); - QCmargin = intern (":margin"); - staticpro (&QCmargin); - QCrelief = intern (":relief"); - staticpro (&QCrelief); - Qpostscript = intern ("postscript"); - staticpro (&Qpostscript); - QCloader = intern (":loader"); - staticpro (&QCloader); - QCbounding_box = intern (":bounding-box"); - staticpro (&QCbounding_box); - QCpt_width = intern (":pt-width"); - staticpro (&QCpt_width); - QCpt_height = intern (":pt-height"); - staticpro (&QCpt_height); - QCindex = intern (":index"); - staticpro (&QCindex); - Qpbm = intern ("pbm"); - staticpro (&Qpbm); - -#if HAVE_XPM - Qxpm = intern ("xpm"); - staticpro (&Qxpm); -#endif - -#if HAVE_JPEG - Qjpeg = intern ("jpeg"); - staticpro (&Qjpeg); -#endif - -#if HAVE_TIFF - Qtiff = intern ("tiff"); - staticpro (&Qtiff); -#endif - -#if HAVE_GIF - Qgif = intern ("gif"); - staticpro (&Qgif); -#endif - -#if HAVE_PNG - Qpng = intern ("png"); - staticpro (&Qpng); -#endif - - defsubr (&Sclear_image_cache); - -#if GLYPH_DEBUG - defsubr (&Simagep); - defsubr (&Slookup_image); -#endif -#endif /* MAC_TODO */ - 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); #if 0 /* MAC_TODO */ defsubr (&Sx_file_dialog); #endif } - -void -init_xfns () -{ - image_types = NULL; - Vimage_types = Qnil; - - define_image_type (&xbm_type); -#if 0 /* NTEMACS_TODO : Image support for W32 */ - define_image_type (&gs_type); - define_image_type (&pbm_type); - -#if HAVE_XPM - define_image_type (&xpm_type); -#endif - -#if HAVE_JPEG - define_image_type (&jpeg_type); -#endif - -#if HAVE_TIFF - define_image_type (&tiff_type); -#endif - -#if HAVE_GIF - define_image_type (&gif_type); -#endif - -#if HAVE_PNG - define_image_type (&png_type); -#endif -#endif /* NTEMACS_TODO */ -} +/* arch-tag: d7591289-f374-4377-b245-12f5dbbb8edc + (do not change this comment) */ diff --git a/src/macgui.h b/src/macgui.h index e04cf448b4a..2bb346e9d30 100644 --- a/src/macgui.h +++ b/src/macgui.h @@ -23,9 +23,6 @@ Boston, MA 02111-1307, USA. */ #ifndef EMACS_MACGUI_H #define EMACS_MACGUI_H -typedef int Pixmap; -typedef int Bitmap; - typedef int Display; /* fix later */ typedef char * XrmDatabase; /* fix later */ @@ -33,12 +30,43 @@ typedef char * XrmDatabase; /* fix later */ typedef unsigned long Time; #if MAC_OSX +#undef mktime +#undef DEBUG +#undef Z +#undef free +#undef malloc +#undef realloc +/* Macros max and min defined in lisp.h conflict with those in + precompiled header Carbon.h. */ +#undef max +#undef min +#undef init_process +#include <Carbon/Carbon.h> +#undef Z +#define Z (current_buffer->text->z) +#undef free +#define free unexec_free +#undef malloc +#define malloc unexec_malloc +#undef realloc +#define realloc unexec_realloc +#undef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#undef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#undef init_process +#define init_process emacs_init_process +#undef INFINITY typedef struct OpaqueWindowPtr* Window; #else -#include <QuickDraw.h> +#include <QuickDraw.h> /* for WindowPtr */ +#include <QDOffscreen.h> /* for GWorldPtr */ +#include <Controls.h> /* for ControlHandle in xdisp.c */ typedef WindowPtr Window; #endif +typedef GWorldPtr Pixmap; + #define FACE_DEFAULT (~0) @@ -198,3 +226,5 @@ typedef struct { #endif /* EMACS_MACGUI_H */ +/* arch-tag: 5a0da49a-35e2-418b-a58c-8a55778ae849 + (do not change this comment) */ diff --git a/src/macmenu.c b/src/macmenu.c index 72fb95fbaa9..06b1b16cf41 100644 --- a/src/macmenu.c +++ b/src/macmenu.c @@ -35,34 +35,7 @@ Boston, MA 02111-1307, USA. */ #include "charset.h" #include "coding.h" -#ifdef MAC_OSX -#undef mktime -#undef DEBUG -#undef Z -#undef free -#undef malloc -#undef realloc -/* Macros max and min defined in lisp.h conflict with those in - precompiled header Carbon.h. */ -#undef max -#undef min -#undef init_process -#include <Carbon/Carbon.h> -#undef Z -#define Z (current_buffer->text->z) -#undef free -#define free unexec_free -#undef malloc -#define malloc unexec_malloc -#undef realloc -#define realloc unexec_realloc -#undef min -#define min(a, b) ((a) < (b) ? (a) : (b)) -#undef max -#define max(a, b) ((a) > (b) ? (a) : (b)) -#undef init_process -#define init_process emacs_init_process -#else /* not MAC_OSX */ +#ifndef MAC_OSX #include <MacTypes.h> #include <Menus.h> #include <QuickDraw.h> @@ -2374,3 +2347,6 @@ The enable predicate for a menu command should check this variable. */); defsubr (&Sx_popup_dialog); #endif } + +/* arch-tag: 40b2c6c7-b8a9-4a49-b930-1b2707184cce + (do not change this comment) */ diff --git a/src/macros.c b/src/macros.c index 1b23f4b3c8c..d0219a3be04 100644 --- a/src/macros.c +++ b/src/macros.c @@ -406,3 +406,6 @@ syms_of_macros () DEFVAR_KBOARD ("last-kbd-macro", Vlast_kbd_macro, doc: /* Last kbd macro defined, as a string or vector; nil if none defined. */); } + +/* arch-tag: d293fcc9-2266-4163-9198-7fa0de12ec9e + (do not change this comment) */ diff --git a/src/macros.h b/src/macros.h index 3f2629c661d..41a32efe2e0 100644 --- a/src/macros.h +++ b/src/macros.h @@ -52,3 +52,6 @@ extern void finalize_kbd_macro_chars P_ ((void)); /* Store a character into kbd macro being defined */ extern void store_kbd_macro_char P_ ((Lisp_Object)); + +/* arch-tag: 8edb7088-682f-4d1f-a4d9-0fbb7284234e + (do not change this comment) */ diff --git a/src/macterm.c b/src/macterm.c index ea4d5b98a8e..44029032bbd 100644 --- a/src/macterm.c +++ b/src/macterm.c @@ -1,5 +1,5 @@ /* Implementation of GUI terminal on the Mac OS. - Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -35,29 +35,6 @@ Boston, MA 02111-1307, USA. */ #endif #ifdef MAC_OSX -#undef mktime -#undef DEBUG -#undef free -#undef malloc -#undef realloc -/* Macros max and min defined in lisp.h conflict with those in - precompiled header Carbon.h. */ -#undef max -#undef min -#undef init_process -#include <Carbon/Carbon.h> -#undef free -#define free unexec_free -#undef malloc -#define malloc unexec_malloc -#undef realloc -#define realloc unexec_realloc -#undef min -#define min(a, b) ((a) < (b) ? (a) : (b)) -#undef max -#define max(a, b) ((a) > (b) ? (a) : (b)) -#undef init_process -#define init_process emacs_init_process /* USE_CARBON_EVENTS determines if the Carbon Event Manager is used to obtain events from the event queue. If set to 0, WaitNextEvent is used instead. */ @@ -253,8 +230,6 @@ extern Lisp_Object Vcommand_line_args, Vsystem_name; extern Lisp_Object Vx_no_window_manager; -extern Lisp_Object Qface, Qmouse_face; - extern int errno; /* A mask of extra modifier bits to put into every keyboard char. */ @@ -305,7 +280,9 @@ static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *)); static void XTframe_rehighlight P_ ((struct frame *)); static void x_frame_rehighlight P_ ((struct x_display_info *)); static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *)); -static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int)); +static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int, + enum text_cursor_kinds)); + static void x_clip_to_row P_ ((struct window *, struct glyph_row *, GC)); static void x_flush P_ ((struct frame *f)); static void x_update_begin P_ ((struct frame *)); @@ -329,15 +306,12 @@ extern void set_frame_menubar (FRAME_PTR, int, int); /* X display function emulation */ -static void +void XFreePixmap (display, pixmap) - Display *display; + Display *display; /* not used */ Pixmap pixmap; { - PixMap *p = (PixMap *) pixmap; - - xfree (p->baseAddr); - xfree (p); + DisposeGWorld (pixmap); } @@ -349,9 +323,9 @@ mac_set_forecolor (unsigned long color) { RGBColor fg_color; - fg_color.red = RED_FROM_ULONG (color) * 256; - fg_color.green = GREEN_FROM_ULONG (color) * 256; - fg_color.blue = BLUE_FROM_ULONG (color) * 256; + fg_color.red = RED16_FROM_ULONG (color); + fg_color.green = GREEN16_FROM_ULONG (color); + fg_color.blue = BLUE16_FROM_ULONG (color); RGBForeColor (&fg_color); } @@ -365,9 +339,9 @@ mac_set_backcolor (unsigned long color) { RGBColor bg_color; - bg_color.red = RED_FROM_ULONG (color) * 256; - bg_color.green = GREEN_FROM_ULONG (color) * 256; - bg_color.blue = BLUE_FROM_ULONG (color) * 256; + bg_color.red = RED16_FROM_ULONG (color); + bg_color.green = GREEN16_FROM_ULONG (color); + bg_color.blue = BLUE16_FROM_ULONG (color); RGBBackColor (&bg_color); } @@ -403,6 +377,23 @@ XDrawLine (display, w, gc, x1, y1, x2, y2) LineTo (x2, y2); } +void +mac_draw_line_to_pixmap (display, p, gc, x1, y1, x2, y2) + Display *display; + Pixmap p; + GC gc; + int x1, y1, x2, y2; +{ + SetGWorld (p, NULL); + + mac_set_colors (gc); + + LockPixels (GetGWorldPixMap (p)); + MoveTo (x1, y1); + LineTo (x2, y2); + UnlockPixels (GetGWorldPixMap (p)); +} + /* Mac version of XClearArea. */ void @@ -469,15 +460,21 @@ XClearWindow (display, w) /* Mac replacement for XCopyArea. */ static void -mac_draw_bitmap (display, w, gc, x, y, bitmap) +mac_draw_bitmap (display, w, gc, x, y, width, height, bits, overlay_p) Display *display; WindowPtr w; GC gc; - int x, y; - BitMap *bitmap; + int x, y, width, height; + unsigned short *bits; + int overlay_p; { + BitMap bitmap; Rect r; + bitmap.rowBytes = sizeof(unsigned short); + bitmap.baseAddr = (char *)bits; + SetRect (&(bitmap.bounds), 0, 0, width, height); + #if TARGET_API_MAC_CARBON SetPort (GetWindowPort (w)); #else @@ -485,19 +482,16 @@ mac_draw_bitmap (display, w, gc, x, y, bitmap) #endif mac_set_colors (gc); - SetRect (&r, x, y, x + bitmap->bounds.right, y + bitmap->bounds.bottom); + SetRect (&r, x, y, x + width, y + height); #if TARGET_API_MAC_CARBON - { - PixMapHandle pmh; - - LockPortBits (GetWindowPort (w)); - pmh = GetPortPixMap (GetWindowPort (w)); - CopyBits (bitmap, (BitMap *) *pmh, &(bitmap->bounds), &r, srcCopy, 0); - UnlockPortBits (GetWindowPort (w)); - } + LockPortBits (GetWindowPort (w)); + CopyBits (&bitmap, GetPortBitMapForCopyBits (GetWindowPort (w)), + &(bitmap.bounds), &r, overlay_p ? srcOr : srcCopy, 0); + UnlockPortBits (GetWindowPort (w)); #else /* not TARGET_API_MAC_CARBON */ - CopyBits (bitmap, &(w->portBits), &(bitmap->bounds), &r, srcCopy, 0); + CopyBits (&bitmap, &(w->portBits), &(bitmap.bounds), &r, + overlay_p ? srcOr : srcCopy, 0); #endif /* not TARGET_API_MAC_CARBON */ } @@ -540,6 +534,23 @@ mac_reset_clipping (display, w) } +/* XBM bits seem to be backward within bytes compared with how + Mac does things. */ +static unsigned char +reflect_byte (orig) + unsigned char orig; +{ + int i; + unsigned char reflected = 0x00; + for (i = 0; i < 8; i++) + { + if (orig & (0x01 << i)) + reflected |= 0x80 >> i; + } + return reflected; +} + + /* Mac replacement for XCreateBitmapFromBitmapData. */ static void @@ -548,18 +559,19 @@ mac_create_bitmap_from_bitmap_data (bitmap, bits, w, h) char *bits; int w, h; { - int bytes_per_row, i, j; + int i, j, w1; + char *p; - bitmap->rowBytes = (w + 15) / 16 * 2; /* must be on word boundary */ + w1 = (w + 7) / 8; /* nb of 8bits elt in X bitmap */ + bitmap->rowBytes = ((w + 15) / 16) * 2; /* nb of 16bits elt in Mac bitmap */ bitmap->baseAddr = xmalloc (bitmap->rowBytes * h); - if (!bitmap->baseAddr) - abort (); - bzero (bitmap->baseAddr, bitmap->rowBytes * h); for (i = 0; i < h; i++) - for (j = 0; j < w; j++) - if (BitTst (bits, i * w + j)) - BitSet (bitmap->baseAddr, i * bitmap->rowBytes * 8 + j); + { + p = bitmap->baseAddr + i * bitmap->rowBytes; + for (j = 0; j < w1; j++) + *p++ = reflect_byte (*bits++); + } SetRect (&(bitmap->bounds), 0, 0, w, h); } @@ -572,6 +584,67 @@ mac_free_bitmap (bitmap) xfree (bitmap->baseAddr); } + +Pixmap +XCreatePixmap (display, w, width, height, depth) + Display *display; /* not used */ + WindowPtr w; + unsigned int width, height; + unsigned int depth; /* not used */ +{ + Pixmap pixmap; + Rect r; + QDErr err; + +#if TARGET_API_MAC_CARBON + SetPort (GetWindowPort (w)); +#else + SetPort (w); +#endif + + SetRect (&r, 0, 0, width, height); + err = NewGWorld (&pixmap, depth, &r, NULL, NULL, 0); + if (err != noErr) + return NULL; + return pixmap; +} + + +Pixmap +XCreatePixmapFromBitmapData (display, w, data, width, height, fg, bg, depth) + Display *display; /* not used */ + WindowPtr w; + char *data; + unsigned int width, height; + unsigned long fg, bg; + unsigned int depth; /* not used */ +{ + Pixmap pixmap; + BitMap bitmap; + + pixmap = XCreatePixmap (display, w, width, height, depth); + if (pixmap == NULL) + return NULL; + + SetGWorld (pixmap, NULL); + mac_create_bitmap_from_bitmap_data (&bitmap, data, width, height); + mac_set_forecolor (fg); + mac_set_backcolor (bg); + LockPixels (GetGWorldPixMap (pixmap)); +#if TARGET_API_MAC_CARBON + CopyBits (&bitmap, GetPortBitMapForCopyBits (pixmap), + &bitmap.bounds, &bitmap.bounds, srcCopy, 0); +#else /* not TARGET_API_MAC_CARBON */ + CopyBits (&bitmap, &(((GrafPtr)pixmap)->portBits), + &bitmap.bounds, &bitmap.bounds, srcCopy, 0); +#endif /* not TARGET_API_MAC_CARBON */ + UnlockPixels (GetGWorldPixMap (pixmap)); + mac_free_bitmap (&bitmap); + + return pixmap; +} + + /* Mac replacement for XFillRectangle. */ static void @@ -597,6 +670,26 @@ XFillRectangle (display, w, gc, x, y, width, height) } +static void +mac_fill_rectangle_to_pixmap (display, p, gc, x, y, width, height) + Display *display; + Pixmap p; + GC gc; + int x, y; + unsigned int width, height; +{ + Rect r; + + SetGWorld (p, NULL); + mac_set_colors (gc); + SetRect (&r, x, y, x + width, y + height); + + LockPixels (GetGWorldPixMap (p)); + PaintRect (&r); /* using foreground color of gc */ + UnlockPixels (GetGWorldPixMap (p)); +} + + /* Mac replacement for XDrawRectangle: dest is a window. */ static void @@ -632,20 +725,15 @@ mac_draw_rectangle_to_pixmap (display, p, gc, x, y, width, height) int x, y; unsigned int width, height; { -#if 0 /* MAC_TODO: draw a rectangle in a PixMap */ Rect r; -#if TARGET_API_MAC_CARBON - SetPort (GetWindowPort (w)); -#else - SetPort (w); -#endif - + SetGWorld (p, NULL); mac_set_colors (gc); - SetRect (&r, x, y, x + width, y + height); + SetRect (&r, x, y, x + width + 1, y + height + 1); + LockPixels (GetGWorldPixMap (p)); FrameRect (&r); /* using foreground color of gc */ -#endif /* 0 */ + UnlockPixels (GetGWorldPixMap (p)); } @@ -760,23 +848,66 @@ mac_copy_area (display, src, dest, gc, src_x, src_y, width, height, dest_x, SetPort (dest); #endif - mac_set_colors (gc); - SetRect (&src_r, src_x, src_y, src_x + width, src_y + height); SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height); + ForeColor (blackColor); + BackColor (whiteColor); + + LockPixels (GetGWorldPixMap (src)); #if TARGET_API_MAC_CARBON - { - PixMapHandle pmh; + LockPortBits (GetWindowPort (dest)); + CopyBits (GetPortBitMapForCopyBits (src), + GetPortBitMapForCopyBits (GetWindowPort (dest)), + &src_r, &dest_r, srcCopy, 0); + UnlockPortBits (GetWindowPort (dest)); +#else /* not TARGET_API_MAC_CARBON */ + CopyBits (&(((GrafPtr)src)->portBits), &(dest->portBits), + &src_r, &dest_r, srcCopy, 0); +#endif /* not TARGET_API_MAC_CARBON */ + UnlockPixels (GetGWorldPixMap (src)); +} - LockPortBits (GetWindowPort (dest)); - pmh = GetPortPixMap (GetWindowPort (dest)); - CopyBits ((BitMap *) &src, (BitMap *) *pmh, &src_r, &dest_r, srcCopy, 0); - UnlockPortBits (GetWindowPort (dest)); - } + +static void +mac_copy_area_with_mask (display, src, mask, dest, gc, src_x, src_y, + width, height, dest_x, dest_y) + Display *display; + Pixmap src, mask; + WindowPtr dest; + GC gc; + int src_x, src_y; + unsigned int width, height; + int dest_x, dest_y; +{ + Rect src_r, dest_r; + +#if TARGET_API_MAC_CARBON + SetPort (GetWindowPort (dest)); +#else + SetPort (dest); +#endif + + SetRect (&src_r, src_x, src_y, src_x + width, src_y + height); + SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height); + + ForeColor (blackColor); + BackColor (whiteColor); + + LockPixels (GetGWorldPixMap (src)); + LockPixels (GetGWorldPixMap (mask)); +#if TARGET_API_MAC_CARBON + LockPortBits (GetWindowPort (dest)); + CopyMask (GetPortBitMapForCopyBits (src), GetPortBitMapForCopyBits (mask), + GetPortBitMapForCopyBits (GetWindowPort (dest)), + &src_r, &src_r, &dest_r); + UnlockPortBits (GetWindowPort (dest)); #else /* not TARGET_API_MAC_CARBON */ - CopyBits ((BitMap *) &src, &(dest->portBits), &src_r, &dest_r, srcCopy, 0); + CopyMask (&(((GrafPtr)src)->portBits), &(((GrafPtr)mask)->portBits), + &(dest->portBits), &src_r, &src_r, &dest_r); #endif /* not TARGET_API_MAC_CARBON */ + UnlockPixels (GetGWorldPixMap (mask)); + UnlockPixels (GetGWorldPixMap (src)); } @@ -811,7 +942,6 @@ mac_scroll_area (display, w, gc, src_x, src_y, width, height, dest_x, dest_y) { #if TARGET_API_MAC_CARBON Rect gw_r, src_r, dest_r; - PixMapHandle pmh; SetRect (&src_r, src_x, src_y, src_x + width, src_y + height); SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height); @@ -822,8 +952,10 @@ mac_scroll_area (display, w, gc, src_x, src_y, width, height, dest_x, dest_y) BackColor (whiteColor); LockPortBits (GetWindowPort (w)); - pmh = GetPortPixMap (GetWindowPort (w)); - CopyBits ((BitMap *) *pmh, (BitMap *) *pmh, &src_r, &dest_r, srcCopy, 0); + { + const BitMap *bitmap = GetPortBitMapForCopyBits (GetWindowPort (w)); + CopyBits (bitmap, bitmap, &src_r, &dest_r, srcCopy, 0); + } UnlockPortBits (GetWindowPort (w)); mac_set_colors (gc); @@ -866,25 +998,67 @@ static void mac_copy_area_to_pixmap (display, src, dest, gc, src_x, src_y, width, height, dest_x, dest_y) Display *display; - Pixmap src; - Pixmap dest; + Pixmap src, dest; GC gc; int src_x, src_y; unsigned int width, height; int dest_x, dest_y; { Rect src_r, dest_r; - int src_right = ((PixMap *) src)->bounds.right; - int src_bottom = ((PixMap *) src)->bounds.bottom; - int w = src_right - src_x; - int h = src_bottom - src_y; - mac_set_colors (gc); + SetGWorld (dest, NULL); + ForeColor (blackColor); + BackColor (whiteColor); - SetRect (&src_r, src_x, src_y, src_right, src_bottom); - SetRect (&dest_r, dest_x, dest_y, dest_x + w, dest_y + h); + SetRect (&src_r, src_x, src_y, src_x + width, src_y + height); + SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height); - CopyBits ((BitMap *) &src, (BitMap *) &dest, &src_r, &dest_r, srcCopy, 0); + LockPixels (GetGWorldPixMap (src)); + LockPixels (GetGWorldPixMap (dest)); +#if TARGET_API_MAC_CARBON + CopyBits (GetPortBitMapForCopyBits (src), GetPortBitMapForCopyBits (dest), + &src_r, &dest_r, srcCopy, 0); +#else /* not TARGET_API_MAC_CARBON */ + CopyBits (&(((GrafPtr)src)->portBits), &(((GrafPtr)dest)->portBits), + &src_r, &dest_r, srcCopy, 0); +#endif /* not TARGET_API_MAC_CARBON */ + UnlockPixels (GetGWorldPixMap (dest)); + UnlockPixels (GetGWorldPixMap (src)); +} + + +static void +mac_copy_area_with_mask_to_pixmap (display, src, mask, dest, gc, src_x, src_y, + width, height, dest_x, dest_y) + Display *display; + Pixmap src, mask, dest; + GC gc; + int src_x, src_y; + unsigned int width, height; + int dest_x, dest_y; +{ + Rect src_r, dest_r; + + SetGWorld (dest, NULL); + ForeColor (blackColor); + BackColor (whiteColor); + + SetRect (&src_r, src_x, src_y, src_x + width, src_y + height); + SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height); + + LockPixels (GetGWorldPixMap (src)); + LockPixels (GetGWorldPixMap (mask)); + LockPixels (GetGWorldPixMap (dest)); +#if TARGET_API_MAC_CARBON + CopyMask (GetPortBitMapForCopyBits (src), GetPortBitMapForCopyBits (mask), + GetPortBitMapForCopyBits (dest), &src_r, &src_r, &dest_r); +#else /* not TARGET_API_MAC_CARBON */ + CopyMask (&(((GrafPtr)src)->portBits), &(((GrafPtr)mask)->portBits), + &(((GrafPtr)dest)->portBits), &src_r, &src_r, &dest_r); +#endif /* not TARGET_API_MAC_CARBON */ + UnlockPixels (GetGWorldPixMap (dest)); + UnlockPixels (GetGWorldPixMap (mask)); + UnlockPixels (GetGWorldPixMap (src)); } @@ -941,7 +1115,7 @@ XGetGCValues (void* ignore, XGCValues *gc, /* Mac replacement for XSetForeground. */ -static void +void XSetForeground (display, gc, color) Display *display; GC gc; @@ -1145,6 +1319,9 @@ x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p) output_cursor.x, output_cursor.y); x_draw_vertical_border (w); + + draw_window_fringes (w); + UNBLOCK_INPUT; } @@ -1241,11 +1418,7 @@ x_after_update_window_line (desired_row) xassert (w); if (!desired_row->mode_line_p && !w->pseudo_window_p) - { - BLOCK_INPUT; - draw_row_fringe_bitmaps (w, desired_row); - UNBLOCK_INPUT; - } + desired_row->redraw_fringe_bitmaps_p = 1; /* When a window has disappeared, make sure that no rest of full-width rows stays visible in the internal border. Could @@ -1297,11 +1470,26 @@ x_draw_fringe_bitmap (w, row, p) XGCValues gcv; GC gc = f->output_data.mac->normal_gc; struct face *face = p->face; + int rowY; /* Must clip because of partially visible lines. */ - x_clip_to_row (w, row, gc); + rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); + if (p->y < rowY) + { + /* Adjust position of "bottom aligned" bitmap on partially + visible last row. */ + int oldY = row->y; + int oldVH = row->visible_height; + row->visible_height = p->h; + row->y -= rowY - p->y; + x_clip_to_row (w, row, gc); + row->y = oldY; + row->visible_height = oldVH; + } + else + x_clip_to_row (w, row, gc); - if (p->bx >= 0) + if (p->bx >= 0 && !p->overlay_p) { XGCValues gcv; gcv.foreground = face->background; @@ -1327,18 +1515,18 @@ x_draw_fringe_bitmap (w, row, p) #endif } - if (p->which != NO_FRINGE_BITMAP) + if (p->which) { - unsigned char *bits = fringe_bitmaps[p->which].bits + p->dh; - BitMap bitmap; + unsigned short *bits = p->bits + p->dh; - mac_create_bitmap_from_bitmap_data (&bitmap, bits, p->wd, p->h); - gcv.foreground = face->foreground; + gcv.foreground = (p->cursor_p + ? (p->overlay_p ? face->background + : f->output_data.mac->cursor_pixel) + : face->foreground); gcv.background = face->background; - mac_draw_bitmap (display, window, &gcv, p->x, p->y, &bitmap); - - mac_free_bitmap (&bitmap); + mac_draw_bitmap (display, window, &gcv, p->x, p->y, + p->wd, p->h, bits, p->overlay_p); } mac_reset_clipping (display, window); @@ -2119,6 +2307,21 @@ x_copy_dpy_color (dpy, cmap, pixel) #endif /* MAC_TODO */ + +/* Brightness beyond which a color won't have its highlight brightness + boosted. + + Nominally, highlight colors for `3d' faces are calculated by + brightening an object's color by a constant scale factor, but this + doesn't yield good results for dark colors, so for colors who's + brightness is less than this value (on a scale of 0-255) have to + use an additional additive factor. + + The value here is set so that the default menu-bar/mode-line color + (grey75) will not have its highlights changed at all. */ +#define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 187 + + /* Allocate a color which is lighter or darker than *COLOR by FACTOR or DELTA. Try a color with RGB values multiplied by FACTOR first. If this produces the same color as COLOR, try a color where all RGB @@ -2134,12 +2337,42 @@ mac_alloc_lighter_color (f, color, factor, delta) int delta; { unsigned long new; + long bright; + + /* On Mac, RGB values are 0-255, not 0-65535, so scale delta. */ + delta /= 256; /* Change RGB values by specified FACTOR. Avoid overflow! */ xassert (factor >= 0); new = RGB_TO_ULONG (min (0xff, (int) (factor * RED_FROM_ULONG (*color))), min (0xff, (int) (factor * GREEN_FROM_ULONG (*color))), min (0xff, (int) (factor * BLUE_FROM_ULONG (*color)))); + + /* Calculate brightness of COLOR. */ + bright = (2 * RED_FROM_ULONG (*color) + 3 * GREEN_FROM_ULONG (*color) + + BLUE_FROM_ULONG (*color)) / 6; + + /* We only boost colors that are darker than + HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */ + if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT) + /* Make an additive adjustment to NEW, because it's dark enough so + that scaling by FACTOR alone isn't enough. */ + { + /* How far below the limit this color is (0 - 1, 1 being darker). */ + double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT; + /* The additive adjustment. */ + int min_delta = delta * dimness * factor / 2; + + if (factor < 1) + new = RGB_TO_ULONG (max (0, min (0xff, (int) (RED_FROM_ULONG (*color)) - min_delta)), + max (0, min (0xff, (int) (GREEN_FROM_ULONG (*color)) - min_delta)), + max (0, min (0xff, (int) (BLUE_FROM_ULONG (*color)) - min_delta))); + else + new = RGB_TO_ULONG (max (0, min (0xff, (int) (min_delta + RED_FROM_ULONG (*color)))), + max (0, min (0xff, (int) (min_delta + GREEN_FROM_ULONG (*color)))), + max (0, min (0xff, (int) (min_delta + BLUE_FROM_ULONG (*color))))); + } + if (new == *color) new = RGB_TO_ULONG (max (0, min (0xff, (int) (delta + RED_FROM_ULONG (*color)))), max (0, min (0xff, (int) (delta + GREEN_FROM_ULONG (*color)))), @@ -2184,7 +2417,8 @@ x_setup_relief_color (f, relief, factor, delta, default_pixel) /* Allocate new color. */ xgcv.foreground = default_pixel; pixel = background; - if (mac_alloc_lighter_color (f, &pixel, factor, delta)) + if (dpyinfo->n_planes != 1 + && mac_alloc_lighter_color (f, &pixel, factor, delta)) { relief->allocated_p = 1; xgcv.foreground = relief->pixel = pixel; @@ -2214,6 +2448,10 @@ x_setup_relief_colors (s) if (s->face->use_box_color_for_shadows_p) color = s->face->box_color; + else if (s->first_glyph->type == IMAGE_GLYPH + && s->img->pixmap + && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0)) + color = IMAGE_BACKGROUND (s->img, s->f, 0); else { XGCValues xgcv; @@ -2247,9 +2485,11 @@ static void x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width, raised_p, left_p, right_p, clip_rect) struct frame *f; - int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p; + int left_x, top_y, right_x, bottom_y, width, left_p, right_p, raised_p; Rect *clip_rect; { + Display *dpy = FRAME_MAC_DISPLAY (f); + Window window = FRAME_MAC_WINDOW (f); int i; GC gc; @@ -2257,41 +2497,41 @@ x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width, gc = f->output_data.mac->white_relief.gc; else gc = f->output_data.mac->black_relief.gc; - mac_set_clip_rectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), clip_rect); + mac_set_clip_rectangle (dpy, window, clip_rect); /* Top. */ for (i = 0; i < width; ++i) - XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc, + XDrawLine (dpy, window, gc, left_x + i * left_p, top_y + i, - right_x + 1 - i * right_p, top_y + i); + right_x - i * right_p, top_y + i); /* Left. */ if (left_p) for (i = 0; i < width; ++i) - XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc, + XDrawLine (dpy, window, gc, left_x + i, top_y + i, left_x + i, bottom_y - i); - mac_reset_clipping (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f)); + mac_reset_clipping (dpy, window); if (raised_p) gc = f->output_data.mac->black_relief.gc; else gc = f->output_data.mac->white_relief.gc; - mac_set_clip_rectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), + mac_set_clip_rectangle (dpy, window, clip_rect); /* Bottom. */ for (i = 0; i < width; ++i) - XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc, + XDrawLine (dpy, window, gc, left_x + i * left_p, bottom_y - i, - right_x + 1 - i * right_p, bottom_y - i); + right_x - i * right_p, bottom_y - i); /* Right. */ if (right_p) for (i = 0; i < width; ++i) - XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc, - right_x - i, top_y + i + 1, right_x - i, bottom_y - i); + XDrawLine (dpy, window, gc, + right_x - i, top_y + i + 1, right_x - i, bottom_y - i - 1); - mac_reset_clipping (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f)); + mac_reset_clipping (dpy, window); } @@ -2306,7 +2546,7 @@ static void x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width, left_p, right_p, clip_rect) struct glyph_string *s; - int left_x, top_y, right_x, bottom_y, left_p, right_p; + int left_x, top_y, right_x, bottom_y, width, left_p, right_p; Rect *clip_rect; { XGCValues xgcv; @@ -2316,21 +2556,21 @@ x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width, /* Top. */ XFillRectangle (s->display, s->window, &xgcv, - left_x, top_y, right_x - left_x, width); + left_x, top_y, right_x - left_x + 1, width); /* Left. */ if (left_p) XFillRectangle (s->display, s->window, &xgcv, - left_x, top_y, width, bottom_y - top_y); + left_x, top_y, width, bottom_y - top_y + 1); /* Bottom. */ XFillRectangle (s->display, s->window, &xgcv, - left_x, bottom_y - width, right_x - left_x, width); + left_x, bottom_y - width + 1, right_x - left_x + 1, width); /* Right. */ if (right_p) XFillRectangle (s->display, s->window, &xgcv, - right_x - width, top_y, width, bottom_y - top_y); + right_x - width + 1, top_y, width, bottom_y - top_y + 1); mac_reset_clipping (s->display, s->window); } @@ -2365,9 +2605,9 @@ x_draw_glyph_string_box (s) width = abs (s->face->box_line_width); raised_p = s->face->box == FACE_RAISED_BOX; left_x = s->x; - right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p - ? last_x - 1 - : min (last_x, s->x + s->background_width) - 1)); + right_x = (s->row->full_width_p && s->extends_to_end_of_line_p + ? last_x - 1 + : min (last_x, s->x + s->background_width) - 1); top_y = s->y; bottom_y = top_y + s->height - 1; @@ -2418,39 +2658,36 @@ x_draw_image_foreground (s) if (s->img->pixmap) { -#if 0 /* MAC_TODO: image mask */ if (s->img->mask) { - /* We can't set both a clip mask and use XSetClipRectangles - because the latter also sets a clip mask. We also can't - trust on the shape extension to be available - (XShapeCombineRegion). So, compute the rectangle to draw - manually. */ - unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin - | GCFunction); - XGCValues xgcv; + Rect nr; XRectangle clip_rect, image_rect, r; - xgcv.clip_mask = s->img->mask; - xgcv.clip_x_origin = x; - xgcv.clip_y_origin = y; - xgcv.function = GXcopy; - XChangeGC (s->display, s->gc, mask, &xgcv); - - get_glyph_string_clip_rect (s, &clip_rect); + get_glyph_string_clip_rect (s, &nr); + CONVERT_TO_XRECT (clip_rect, nr); image_rect.x = x; image_rect.y = y; image_rect.width = s->img->width; image_rect.height = s->img->height; if (x_intersect_rectangles (&clip_rect, &image_rect, &r)) - XCopyArea (s->display, s->img->pixmap, s->window, s->gc, - r.x - x, r.y - y, r.width, r.height, r.x, r.y); + mac_copy_area_with_mask (s->display, s->img->pixmap, s->img->mask, + s->window, s->gc, r.x - x, r.y - y, + r.width, r.height, r.x, r.y); } else -#endif /* MAC_TODO */ { - mac_copy_area (s->display, s->img->pixmap, s->window, s->gc, - 0, 0, s->img->width, s->img->height, x, y); + Rect nr; + XRectangle clip_rect, image_rect, r; + + get_glyph_string_clip_rect (s, &nr); + CONVERT_TO_XRECT (clip_rect, nr); + image_rect.x = x; + image_rect.y = y; + image_rect.width = s->img->width; + image_rect.height = s->img->height; + if (x_intersect_rectangles (&clip_rect, &image_rect, &r)) + mac_copy_area (s->display, s->img->pixmap, s->window, s->gc, + r.x - x, r.y - y, r.width, r.height, r.x, r.y); /* When the image has a mask, we can expect that at least part of a mouse highlight or a block cursor will @@ -2474,7 +2711,6 @@ x_draw_image_foreground (s) } - /* Draw a relief around the image glyph string S. */ static void @@ -2547,30 +2783,12 @@ x_draw_image_foreground_1 (s, pixmap) if (s->img->pixmap) { -#if 0 /* MAC_TODO: image mask */ if (s->img->mask) - { - /* We can't set both a clip mask and use XSetClipRectangles - because the latter also sets a clip mask. We also can't - trust on the shape extension to be available - (XShapeCombineRegion). So, compute the rectangle to draw - manually. */ - unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin - | GCFunction); - XGCValues xgcv; - - xgcv.clip_mask = s->img->mask; - xgcv.clip_x_origin = x; - xgcv.clip_y_origin = y; - xgcv.function = GXcopy; - XChangeGC (s->display, s->gc, mask, &xgcv); - - XCopyArea (s->display, s->img->pixmap, pixmap, s->gc, - 0, 0, s->img->width, s->img->height, x, y); - XSetClipMask (s->display, s->gc, None); - } + mac_copy_area_with_mask_to_pixmap (s->display, s->img->pixmap, + s->img->mask, pixmap, s->gc, + 0, 0, s->img->width, s->img->height, + x, y); else -#endif /* MAC_TODO */ { mac_copy_area_to_pixmap (s->display, s->img->pixmap, pixmap, s->gc, 0, 0, s->img->width, s->img->height, x, y); @@ -2585,15 +2803,16 @@ x_draw_image_foreground_1 (s, pixmap) { int r = s->img->relief; if (r < 0) r = -r; - mac_draw_rectangle_to_pixmap (s->display, pixmap, s->gc, x - r, y - r, - s->img->width + r*2 - 1, s->img->height + r*2 - 1); + mac_draw_rectangle (s->display, s->window, s->gc, x - r, y - r, + s->img->width + r*2 - 1, + s->img->height + r*2 - 1); } } } else /* Draw a rectangle if image could not be loaded. */ mac_draw_rectangle_to_pixmap (s->display, pixmap, s->gc, x, y, - s->img->width - 1, s->img->height - 1); + s->img->width - 1, s->img->height - 1); } @@ -2626,7 +2845,7 @@ x_draw_glyph_string_bg_rect (s, x, y, w, h) | s->face->box | | +------------------------- - | | s->img->vmargin + | | s->img->margin | | | | +------------------- | | | the image @@ -2645,6 +2864,7 @@ x_draw_image_glyph_string (s) height = s->height - 2 * box_line_vwidth; + /* Fill background with face under the image. Do it only if row is taller than image or if image has a clip mask to reduce flickering. */ @@ -2652,9 +2872,7 @@ x_draw_image_glyph_string (s) if (height > s->img->height || s->img->hmargin || s->img->vmargin -#if 0 /* TODO: image mask */ || s->img->mask -#endif || s->img->pixmap == 0 || s->width != s->background_width) { @@ -2664,25 +2882,21 @@ x_draw_image_glyph_string (s) x = s->x; y = s->y + box_line_vwidth; -#if 0 /* TODO: image mask */ + if (s->img->mask) { /* Create a pixmap as large as the glyph string. Fill it with the background color. Copy the image to it, using its mask. Copy the temporary pixmap to the display. */ - Screen *screen = FRAME_X_SCREEN (s->f); - int depth = DefaultDepthOfScreen (screen); + int depth = one_mac_display_info.n_planes; /* Create a pixmap as large as the glyph string. */ pixmap = XCreatePixmap (s->display, s->window, s->background_width, s->height, depth); - /* Don't clip in the following because we're working on the - pixmap. */ - XSetClipMask (s->display, s->gc, None); - /* Fill the pixmap with the background color/stipple. */ +#if 0 /* TODO: stipple */ if (s->stippled_p) { /* Fill background with a stipple pattern. */ @@ -2692,18 +2906,19 @@ x_draw_image_glyph_string (s) XSetFillStyle (s->display, s->gc, FillSolid); } else +#endif { XGCValues xgcv; XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv); XSetForeground (s->display, s->gc, xgcv.background); - XFillRectangle (s->display, pixmap, s->gc, - 0, 0, s->background_width, s->height); + mac_fill_rectangle_to_pixmap (s->display, pixmap, s->gc, + 0, 0, s->background_width, + s->height); XSetForeground (s->display, s->gc, xgcv.foreground); } } else -#endif x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height); s->background_filled_p = 1; @@ -2715,7 +2930,7 @@ x_draw_image_glyph_string (s) x_draw_image_foreground_1 (s, pixmap); x_set_glyph_string_clipping (s); mac_copy_area (s->display, pixmap, s->window, s->gc, - 0, 0, s->background_width, s->height, s->x, s->y); + 0, 0, s->background_width, s->height, s->x, s->y); mac_reset_clipping (s->display, s->window); XFreePixmap (s->display, pixmap); } @@ -2752,10 +2967,10 @@ x_draw_stretch_glyph_string (s) /* Clear rest using the GC of the original non-cursor face. */ if (width < s->background_width) { - GC gc = s->face->gc; int x = s->x + width, y = s->y; int w = s->background_width - width, h = s->height; Rect r; + GC gc; if (s->row->mouse_face_p && cursor_in_mouse_face_p (s->w)) @@ -2815,7 +3030,6 @@ x_draw_glyph_string (s) x_set_glyph_string_gc (s->next); x_set_glyph_string_clipping (s->next); x_draw_glyph_string_background (s->next, 1); - } /* Set up S->gc, set clipping and draw S. */ @@ -2852,7 +3066,7 @@ x_draw_glyph_string (s) if (s->for_overlaps_p) s->background_filled_p = 1; else - x_draw_glyph_string_background (s, 0); + x_draw_glyph_string_background (s, 0); x_draw_glyph_string_foreground (s); break; @@ -2929,9 +3143,9 @@ x_draw_glyph_string (s) } } - /* Draw relief. */ + /* Draw relief if not yet drawn. */ if (!relief_drawn_p && s->face->box != FACE_NO_BOX) - x_draw_glyph_string_box (s); + x_draw_glyph_string_box (s); } /* Reset clipping. */ @@ -2951,7 +3165,6 @@ mac_shift_glyphs_for_insert (f, x, y, width, height, shift_by) x + shift_by, y); } - /* Delete N glyphs at the nominal cursor position. Not implemented for X frames. */ @@ -3006,6 +3219,7 @@ x_clear_frame () #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) + /* Subtract the `struct timeval' values X and Y, storing the result in *RESULT. Return 1 if the difference is negative, otherwise 0. */ @@ -3109,7 +3323,7 @@ XTring_bell () This, and those operations, are used only within an update that is bounded by calls to x_update_begin and x_update_end. */ -void +static void XTset_terminal_window (n) register int n; { @@ -3145,7 +3359,7 @@ x_scroll_run (w, run) /* Get frame-relative bounding box of the text display area of W, without mode lines. Include in this box the left and right - fringes of W. */ + fringe of W. */ window_box (w, -1, &x, &y, &width, &height); from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y); @@ -3267,8 +3481,6 @@ static void XTframe_rehighlight (frame) struct frame *frame; { - - x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame)); } @@ -4409,13 +4621,6 @@ x_draw_hollow_cursor (w, row) struct glyph *cursor_glyph; GC gc; - /* Compute frame-relative coordinates from window-relative - coordinates. */ - x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); - y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y) - + row->ascent - w->phys_cursor_ascent); - h = row->height - 1; - /* Get the glyph the cursor is on. If we can't tell because the current matrix is invalid or such, give up. */ cursor_glyph = get_phys_cursor_glyph (w); @@ -4430,6 +4635,20 @@ x_draw_hollow_cursor (w, row) if (cursor_glyph->type == STRETCH_GLYPH && !x_stretch_cursor_p) wd = min (FRAME_COLUMN_WIDTH (f), wd); + w->phys_cursor_width = wd; + + /* Compute frame-relative coordinates from window-relative + coordinates. */ + x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); + y = WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y); + + /* Compute the proper height and ascent of the rectangle, based + on the actual glyph. Using the full height of the row looks + bad when there are tall images on that row. */ + h = max (FRAME_LINE_HEIGHT (f), cursor_glyph->ascent + cursor_glyph->descent); + if (h < row->height) + y += row->ascent /* - w->phys_cursor_ascent */ + cursor_glyph->descent - h; + h--; /* The foreground of cursor_gc is typically the same as the normal background color, which can cause the cursor box to be invisible. */ @@ -4456,35 +4675,49 @@ x_draw_hollow_cursor (w, row) --gerd. */ static void -x_draw_bar_cursor (w, row, width) +x_draw_bar_cursor (w, row, width, kind) struct window *w; struct glyph_row *row; int width; + enum text_cursor_kinds kind; { - /* If cursor hpos is out of bounds, don't draw garbage. This can - happen in mini-buffer windows when switching between echo area - glyphs and mini-buffer. */ - if (w->phys_cursor.hpos < row->used[TEXT_AREA]) + struct frame *f = XFRAME (w->frame); + struct glyph *cursor_glyph; + + /* If cursor is out of bounds, don't draw garbage. This can happen + in mini-buffer windows when switching between echo area glyphs + and mini-buffer. */ + cursor_glyph = get_phys_cursor_glyph (w); + if (cursor_glyph == NULL) + return; + + /* If on an image, draw like a normal cursor. That's usually better + visible than drawing a bar, esp. if the image is large so that + the bar might not be in the window. */ + if (cursor_glyph->type == IMAGE_GLYPH) { - struct frame *f = XFRAME (w->frame); - struct glyph *cursor_glyph; - GC gc; - int x; - unsigned long mask; + struct glyph_row *row; + row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos); + draw_phys_cursor_glyph (w, row, DRAW_CURSOR); + } + else + { + Display *dpy = FRAME_MAC_DISPLAY (f); + Window window = FRAME_MAC_WINDOW (f); + GC gc = FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc; + unsigned long mask = GCForeground | GCBackground; + struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id); XGCValues xgcv; - Display *dpy; - Window window; - cursor_glyph = get_phys_cursor_glyph (w); - if (cursor_glyph == NULL) - return; - - xgcv.background = f->output_data.mac->cursor_pixel; - xgcv.foreground = f->output_data.mac->cursor_pixel; - mask = GCForeground | GCBackground; - dpy = FRAME_MAC_DISPLAY (f); - window = FRAME_MAC_WINDOW (f); - gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc; + /* If the glyph's background equals the color we normally draw + the bar cursor in, the bar cursor in its normal color is + invisible. Use the glyph's foreground color instead in this + case, on the assumption that the glyph's colors are chosen so + that the glyph is legible. */ + if (face->background == f->output_data.mac->cursor_pixel) + xgcv.background = xgcv.foreground = face->foreground; + else + xgcv.background = xgcv.foreground = f->output_data.mac->cursor_pixel; if (gc) XChangeGC (dpy, gc, mask, &xgcv); @@ -4496,14 +4729,24 @@ x_draw_bar_cursor (w, row, width) if (width < 0) width = FRAME_CURSOR_WIDTH (f); + width = min (cursor_glyph->pixel_width, width); - x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); + w->phys_cursor_width = width; x_clip_to_row (w, row, gc); - XFillRectangle (dpy, window, gc, - x, - WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y), - min (cursor_glyph->pixel_width, width), - row->height); + + if (kind == BAR_CURSOR) + XFillRectangle (dpy, window, gc, + WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x), + WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y), + width, row->height); + else + XFillRectangle (dpy, window, gc, + WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x), + WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y + + row->height - width), + cursor_glyph->pixel_width, + width); + mac_reset_clipping (dpy, FRAME_MAC_WINDOW (f)); } } @@ -4545,9 +4788,15 @@ mac_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, act if (on_p) { w->phys_cursor_type = cursor_type; - w->phys_cursor_width = cursor_width; w->phys_cursor_on_p = 1; + if (glyph_row->exact_window_width_line_p + && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA]) + { + glyph_row->cursor_in_fringe_p = 1; + draw_fringe_bitmap (w, glyph_row, 0); + } + else switch (cursor_type) { case HOLLOW_BOX_CURSOR: @@ -4558,13 +4807,16 @@ mac_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, act draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); break; - case HBAR_CURSOR: - /* TODO. For now, just draw bar cursor. */ case BAR_CURSOR: - x_draw_bar_cursor (w, glyph_row, cursor_width); + x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR); + break; + + case HBAR_CURSOR: + x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR); break; case NO_CURSOR: + w->phys_cursor_width = 0; break; default: @@ -5089,6 +5341,8 @@ x_make_frame_visible (f) FRAME_SAMPLE_VISIBILITY (f); } } +#else + UNBLOCK_INPUT; #endif /* MAC_TODO */ } @@ -5145,10 +5399,10 @@ x_iconify_frame (f) } -/* Destroy the X window of frame F. */ +/* Free X resources of frame F. */ void -x_destroy_window (f) +x_free_frame_resources (f) struct frame *f; { struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); @@ -5158,10 +5412,15 @@ x_destroy_window (f) DisposeWindow (FRAME_MAC_WINDOW (f)); free_frame_menubar (f); - free_frame_faces (f); + + if (FRAME_FACE_CACHE (f)) + free_frame_faces (f); + + x_free_gcs (f); xfree (f->output_data.mac); - f->output_data.mac = 0; + f->output_data.mac = NULL; + if (f == dpyinfo->x_focus_frame) dpyinfo->x_focus_frame = 0; if (f == dpyinfo->x_focus_event_frame) @@ -5169,8 +5428,6 @@ x_destroy_window (f) if (f == dpyinfo->x_highlight_frame) dpyinfo->x_highlight_frame = 0; - dpyinfo->reference_count--; - if (f == dpyinfo->mouse_face_mouse_frame) { dpyinfo->mouse_face_beg_row @@ -5184,6 +5441,21 @@ x_destroy_window (f) UNBLOCK_INPUT; } + + +/* Destroy the X window of frame F. */ + +void +x_destroy_window (f) + struct frame *f; +{ + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + + x_free_frame_resources (f); + + dpyinfo->reference_count--; +} + /* Setting window manager hints. */ @@ -5450,6 +5722,7 @@ char **font_name_table = NULL; int font_name_table_size = 0; int font_name_count = 0; +#if 0 /* compare two strings ignoring case */ static int stricmp (const char *s, const char *t) @@ -5529,13 +5802,53 @@ mac_font_match (char *mf, char *xf) && wildstrieq (m_charset, x_charset)) || mac_font_pattern_match (mf, xf); } +#endif + +static Lisp_Object Qbig5, Qcn_gb, Qsjis, Qeuc_kr; + +static void +decode_mac_font_name (char *name, int size, short scriptcode) +{ + Lisp_Object coding_system; + struct coding_system coding; + char *buf; + + switch (scriptcode) + { + case smTradChinese: + coding_system = Qbig5; + break; + case smSimpChinese: + coding_system = Qcn_gb; + break; + case smJapanese: + coding_system = Qsjis; + break; + case smKorean: + coding_system = Qeuc_kr; + break; + default: + return; + } + + setup_coding_system (coding_system, &coding); + coding.src_multibyte = 0; + coding.dst_multibyte = 1; + coding.mode |= CODING_MODE_LAST_BLOCK; + coding.composing = COMPOSITION_DISABLED; + buf = (char *) alloca (size); + + decode_coding (&coding, name, buf, strlen (name), size - 1); + bcopy (buf, name, coding.produced); + name[coding.produced] = '\0'; +} static char * mac_to_x_fontname (char *name, int size, Style style, short scriptcode) { char foundry[32], family[32], cs[32]; - char xf[255], *result, *p; + char xf[256], *result, *p; if (sscanf (name, "%31[^-]-%31[^-]-%31s", foundry, family, cs) != 3) { @@ -5594,6 +5907,8 @@ static void x_font_name_to_mac_font_name (char *xf, char *mf) { char foundry[32], family[32], weight[20], slant[2], cs[32]; + Lisp_Object coding_system = Qnil; + struct coding_system coding; strcpy (mf, ""); @@ -5603,13 +5918,29 @@ x_font_name_to_mac_font_name (char *xf, char *mf) foundry, family, weight, slant, cs) != 5) return; - if (strcmp (cs, "big5-0") == 0 || strcmp (cs, "gb2312.1980-0") == 0 - || strcmp (cs, "jisx0208.1983-sjis") == 0 - || strcmp (cs, "jisx0201.1976-0") == 0 - || strcmp (cs, "ksc5601.1989-0") == 0 || strcmp (cs, "mac-roman") == 0) - strcpy(mf, family); + if (strcmp (cs, "big5-0") == 0) + coding_system = Qbig5; + else if (strcmp (cs, "gb2312.1980-0") == 0) + coding_system = Qcn_gb; + else if (strcmp (cs, "jisx0208.1983-sjis") == 0 + || strcmp (cs, "jisx0201.1976-0") == 0) + coding_system = Qsjis; + else if (strcmp (cs, "ksc5601.1989-0") == 0) + coding_system = Qeuc_kr; + else if (strcmp (cs, "mac-roman") == 0) + strcpy (mf, family); else - sprintf(mf, "%s-%s-%s", foundry, family, cs); + sprintf (mf, "%s-%s-%s", foundry, family, cs); + + if (!NILP (coding_system)) + { + setup_coding_system (coding_system, &coding); + coding.src_multibyte = 1; + coding.dst_multibyte = 1; + coding.mode |= CODING_MODE_LAST_BLOCK; + encode_coding (&coding, family, mf, strlen (family), sizeof (Str32) - 1); + mf[coding.produced] = '\0'; + } } @@ -5673,36 +6004,45 @@ init_font_name_table () if (FMGetFontFamilyName (ff, name) != noErr) break; p2cstr (name); + if (*name == '.') + continue; sc = FontToScript (ff); + decode_mac_font_name (name, sizeof (name), sc); /* Point the instance iterator at the current font family. */ - if (FMResetFontFamilyInstanceIterator(ff, &ffii) != noErr) + if (FMResetFontFamilyInstanceIterator (ff, &ffii) != noErr) break; while (FMGetNextFontFamilyInstance (&ffii, &font, &style, &size) == noErr) - if (size == 0) - { - add_font_name_table_entry (mac_to_x_fontname (name, size, - style, sc)); - add_font_name_table_entry (mac_to_x_fontname (name, size, - italic, sc)); - add_font_name_table_entry (mac_to_x_fontname (name, size, - bold, sc)); - add_font_name_table_entry (mac_to_x_fontname (name, size, - italic | bold, - sc)); - } - else - { + { + /* Both jisx0208.1983-sjis and jisx0201.1976-0 parts are + contained in Apple Japanese (SJIS) font. */ + again: + if (size == 0) + { + add_font_name_table_entry (mac_to_x_fontname (name, size, + style, sc)); + add_font_name_table_entry (mac_to_x_fontname (name, size, + italic, sc)); + add_font_name_table_entry (mac_to_x_fontname (name, size, + bold, sc)); + add_font_name_table_entry (mac_to_x_fontname (name, size, + italic | bold, + sc)); + } + else add_font_name_table_entry (mac_to_x_fontname (name, size, style, sc)); - if (smJapanese == sc) - add_font_name_table_entry (mac_to_x_fontname (name, size, - style, - -smJapanese)); - } + if (sc == smJapanese) + { + sc = -smJapanese; + goto again; + } + else if (sc == -smJapanese) + sc = smJapanese; + } } /* Dispose of the iterators. */ @@ -5744,6 +6084,7 @@ init_font_name_table () TextFont (fontnum); scriptcode = FontToScript (fontnum); + decode_mac_font_name (name, sizeof (name), scriptcode); do { HLock (font_handle); @@ -5778,9 +6119,9 @@ init_font_name_table () assc_entry->fontSize, assc_entry->fontStyle, scriptcode); - /* Both jisx0208.1983-sjis and - jisx0201.1976-sjis parts are contained in - Apple Japanese (SJIS) font. */ + /* Both jisx0208.1983-sjis and jisx0201.1976-0 + parts are contained in Apple Japanese (SJIS) + font. */ if (smJapanese == scriptcode) { font_name_table[font_name_count++] @@ -5807,6 +6148,145 @@ init_font_name_table () } +enum xlfd_scalable_field_index + { + XLFD_SCL_PIXEL_SIZE, + XLFD_SCL_POINT_SIZE, + XLFD_SCL_AVGWIDTH, + XLFD_SCL_LAST + }; + +static int xlfd_scalable_fields[] = + { + 6, /* PIXEL_SIZE */ + 7, /* POINT_SIZE */ + 11, /* AVGWIDTH */ + -1 + }; + +static Lisp_Object +mac_do_list_fonts (pattern, maxnames) + char *pattern; + int maxnames; +{ + int i, n_fonts = 0; + Lisp_Object font_list = Qnil, pattern_regex, fontname; + char *regex = (char *) alloca (strlen (pattern) * 2 + 3); + char scaled[256]; + char *ptr; + int scl_val[XLFD_SCL_LAST], *field, *val; + + for (i = 0; i < XLFD_SCL_LAST; i++) + scl_val[i] = -1; + + /* If the pattern contains 14 dashes and one of PIXEL_SIZE, + POINT_SIZE, and AVGWIDTH fields is explicitly specified, scalable + fonts are scaled according to the specified size. */ + ptr = pattern; + i = 0; + field = xlfd_scalable_fields; + val = scl_val; + if (*ptr == '-') + do + { + ptr++; + if (i == *field) + { + if ('1' <= *ptr && *ptr <= '9') + { + *val = *ptr++ - '0'; + while ('0' <= *ptr && *ptr <= '9' && *val < 10000) + *val = *val * 10 + *ptr++ - '0'; + if (*ptr != '-') + *val = -1; + } + field++; + val++; + } + ptr = strchr (ptr, '-'); + i++; + } + while (ptr && i < 14); + + if (i == 14 && ptr == NULL) + { + if (scl_val[XLFD_SCL_POINT_SIZE] > 0) + { + scl_val[XLFD_SCL_PIXEL_SIZE] = scl_val[XLFD_SCL_POINT_SIZE] / 10; + scl_val[XLFD_SCL_AVGWIDTH] = scl_val[XLFD_SCL_POINT_SIZE]; + } + else if (scl_val[XLFD_SCL_PIXEL_SIZE] > 0) + { + scl_val[XLFD_SCL_POINT_SIZE] = + scl_val[XLFD_SCL_AVGWIDTH] = scl_val[XLFD_SCL_PIXEL_SIZE] * 10; + } + else if (scl_val[XLFD_SCL_AVGWIDTH] > 0) + { + scl_val[XLFD_SCL_PIXEL_SIZE] = scl_val[XLFD_SCL_AVGWIDTH] / 10; + scl_val[XLFD_SCL_POINT_SIZE] = scl_val[XLFD_SCL_AVGWIDTH]; + } + } + else + scl_val[XLFD_SCL_PIXEL_SIZE] = -1; + + ptr = regex; + *ptr++ = '^'; + + /* Turn pattern into a regexp and do a regexp match. */ + for (; *pattern; pattern++) + { + if (*pattern == '?') + *ptr++ = '.'; + else if (*pattern == '*') + { + *ptr++ = '.'; + *ptr++ = '*'; + } + else + *ptr++ = tolower (*pattern); + } + *ptr = '$'; + *(ptr + 1) = '\0'; + + pattern_regex = build_string (regex); + + for (i = 0; i < font_name_count; i++) + { + fontname = build_string (font_name_table[i]); + if (fast_string_match (pattern_regex, fontname) >= 0) + { + font_list = Fcons (fontname, font_list); + + n_fonts++; + if (maxnames > 0 && n_fonts >= maxnames) + break; + } + else if (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 + && (ptr = strstr (font_name_table[i], "-0-0-75-75-m-0-"))) + { + int former_len = ptr - font_name_table[i]; + + memcpy (scaled, font_name_table[i], former_len); + sprintf (scaled + former_len, + "-%d-%d-75-75-m-%d-%s", + scl_val[XLFD_SCL_PIXEL_SIZE], + scl_val[XLFD_SCL_POINT_SIZE], + scl_val[XLFD_SCL_AVGWIDTH], + ptr + sizeof ("-0-0-75-75-m-0-") - 1); + fontname = build_string (scaled); + if (fast_string_match (pattern_regex, fontname) >= 0) + { + font_list = Fcons (fontname, font_list); + + n_fonts++; + if (maxnames > 0 && n_fonts >= maxnames) + break; + } + } + } + return font_list; +} + /* Return a list of at most MAXNAMES font specs matching the one in PATTERN. Cache matching fonts for patterns in dpyinfo->name_list_element to avoid looking them up again by @@ -5819,11 +6299,7 @@ x_list_fonts (struct frame *f, int size, int maxnames) { - char *ptnstr; Lisp_Object newlist = Qnil, tem, key; - int n_fonts = 0; - int i; - struct gcpro gcpro1, gcpro2; struct mac_display_info *dpyinfo = f ? FRAME_MAC_DISPLAY_INFO (f) : NULL; if (font_name_table == NULL) /* Initialize when first used. */ @@ -5842,27 +6318,10 @@ x_list_fonts (struct frame *f, } } - ptnstr = SDATA (pattern); - - GCPRO2 (pattern, newlist); - - /* Scan and matching bitmap fonts. */ - for (i = 0; i < font_name_count; i++) - { - if (mac_font_pattern_match (font_name_table[i], ptnstr)) - { - newlist = Fcons (build_string (font_name_table[i]), newlist); - - n_fonts++; - if (maxnames > 0 && n_fonts >= maxnames) - break; - } - } + newlist = mac_do_list_fonts (SDATA (pattern), maxnames); /* MAC_TODO: add code for matching outline fonts here */ - UNGCPRO; - if (dpyinfo) { XSETCDR (dpyinfo->name_list_element, @@ -6022,14 +6481,12 @@ XLoadQueryFont (Display *dpy, char *fontname) name = fontname; else { - for (i = 0; i < font_name_count; i++) - if (mac_font_pattern_match (font_name_table[i], fontname)) - break; + Lisp_Object matched_fonts; - if (i >= font_name_count) - return NULL; - - name = font_name_table[i]; + matched_fonts = mac_do_list_fonts (fontname, 1); + if (NILP (matched_fonts)) + return NULL; + name = SDATA (XCAR (matched_fonts)); } GetPort (&port); /* save the current font number used */ @@ -6151,7 +6608,8 @@ XLoadQueryFont (Display *dpy, char *fontname) for (c = 0x20; c <= 0xff; c++) { font->per_char[c - 0x20] = font->max_bounds; - font->per_char[c - 0x20].width = CharWidth (c); + font->per_char[c - 0x20].width = + font->per_char[c - 0x20].rbearing = CharWidth (c); } } } @@ -6240,6 +6698,7 @@ x_load_font (f, fontname, size) /* Now fill in the slots of *FONTP. */ BLOCK_INPUT; + bzero (fontp, sizeof (*fontp)); fontp->font = font; fontp->font_idx = i; fontp->name = (char *) xmalloc (strlen (font->fontname) + 1); @@ -6373,81 +6832,6 @@ x_find_ccl_program (fontp) -/*********************************************************************** - Initialization - ***********************************************************************/ - -#ifdef USE_X_TOOLKIT -static XrmOptionDescRec emacs_options[] = { - {"-geometry", ".geometry", XrmoptionSepArg, NULL}, - {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"}, - - {"-internal-border-width", "*EmacsScreen.internalBorderWidth", - XrmoptionSepArg, NULL}, - {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL}, - - {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL}, - {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL}, - {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL}, - {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL}, - {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL}, - {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL}, - {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL} -}; -#endif /* USE_X_TOOLKIT */ - -static int x_initialized; - -#ifdef MULTI_KBOARD -/* Test whether two display-name strings agree up to the dot that separates - the screen number from the server number. */ -static int -same_x_server (name1, name2) - char *name1, *name2; -{ - int seen_colon = 0; - unsigned char *system_name = SDATA (Vsystem_name); - int system_name_length = strlen (system_name); - int length_until_period = 0; - - while (system_name[length_until_period] != 0 - && system_name[length_until_period] != '.') - length_until_period++; - - /* Treat `unix' like an empty host name. */ - if (! strncmp (name1, "unix:", 5)) - name1 += 4; - if (! strncmp (name2, "unix:", 5)) - name2 += 4; - /* Treat this host's name like an empty host name. */ - if (! strncmp (name1, system_name, system_name_length) - && name1[system_name_length] == ':') - name1 += system_name_length; - if (! strncmp (name2, system_name, system_name_length) - && name2[system_name_length] == ':') - name2 += system_name_length; - /* Treat this host's domainless name like an empty host name. */ - if (! strncmp (name1, system_name, length_until_period) - && name1[length_until_period] == ':') - name1 += length_until_period; - if (! strncmp (name2, system_name, length_until_period) - && name2[length_until_period] == ':') - name2 += length_until_period; - - for (; *name1 != '\0' && *name1 == *name2; name1++, name2++) - { - if (*name1 == ':') - seen_colon++; - if (seen_colon && *name1 == '.') - return 1; - } - return (seen_colon - && (*name1 == '.' || *name1 == '\0') - && (*name2 == '.' || *name2 == '\0')); -} -#endif - - /* The Mac Event loop code */ #ifndef MAC_OSX @@ -6509,12 +6893,19 @@ static long app_sleep_time = WNE_SLEEP_AT_RESUME; Boolean terminate_flag = false; +/* Contains the string "reverse", which is a constant for mouse button emu.*/ +Lisp_Object Qreverse; + /* True if using command key as meta key. */ Lisp_Object Vmac_command_key_is_meta; /* True if the ctrl and meta keys should be reversed. */ Lisp_Object Vmac_reverse_ctrl_meta; +/* True if the option and command modifiers should be used to emulate + a three button mouse */ +Lisp_Object Vmac_emulate_three_button_mouse; + #if USE_CARBON_EVENTS /* True if the mouse wheel button (i.e. button 4) should map to mouse-2, instead of mouse-3. */ @@ -6587,6 +6978,20 @@ mac_to_emacs_modifiers (EventModifiers mods) return result; } +static int +mac_get_emulated_btn ( UInt32 modifiers ) +{ + int result = 0; + if (Vmac_emulate_three_button_mouse != Qnil) { + int cmdIs3 = (Vmac_emulate_three_button_mouse != Qreverse); + if (modifiers & controlKey) + result = cmdIs3 ? 2 : 1; + else if (modifiers & optionKey) + result = cmdIs3 ? 1 : 2; + } + return result; +} + #if USE_CARBON_EVENTS /* Obtains the event modifiers from the event ref and then calls mac_to_emacs_modifiers. */ @@ -6596,6 +7001,11 @@ mac_event_to_emacs_modifiers (EventRef eventRef) UInt32 mods = 0; GetEventParameter (eventRef, kEventParamKeyModifiers, typeUInt32, NULL, sizeof (UInt32), NULL, &mods); + if (Vmac_emulate_three_button_mouse != Qnil && + GetEventClass(eventRef) == kEventClassMouse) + { + mods &= ~(optionKey & cmdKey); + } return mac_to_emacs_modifiers (mods); } @@ -6610,7 +7020,14 @@ mac_get_mouse_btn (EventRef ref) switch (result) { case kEventMouseButtonPrimary: - return 0; + if (Vmac_emulate_three_button_mouse == Qnil) + return 0; + else { + UInt32 mods = 0; + GetEventParameter (ref, kEventParamKeyModifiers, typeUInt32, NULL, + sizeof (UInt32), NULL, &mods); + return mac_get_emulated_btn(mods); + } case kEventMouseButtonSecondary: return NILP (Vmac_wheel_button_is_mouse_2) ? 1 : 2; case kEventMouseButtonTertiary: @@ -6719,8 +7136,8 @@ do_check_ram_size (void) if (Gestalt (gestaltPhysicalRAMSize, &physical_ram_size) != noErr || Gestalt (gestaltLogicalRAMSize, &logical_ram_size) != noErr - || physical_ram_size > 256 * 1024 * 1024 - || logical_ram_size > 256 * 1024 * 1024) + || physical_ram_size > (1 << VALBITS) + || logical_ram_size > (1 << VALBITS)) { StopAlert (RAM_TOO_LARGE_ALERT_ID, NULL); exit (1); @@ -7519,7 +7936,9 @@ main (void) do_get_menus (); +#ifndef USE_LSB_TAG do_check_ram_size (); +#endif init_emacs_passwd_dir (); @@ -7597,8 +8016,9 @@ keycode_to_xkeysym (int keyCode, int *xKeySym) /* Emacs calls this whenever it wants to read an input event from the user. */ int -XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) +XTread_socket (int sd, int expected, struct input_event *hold_quit) { + struct input_event inev; int count = 0; #if USE_CARBON_EVENTS OSStatus rneResult; @@ -7623,9 +8043,6 @@ XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) /* So people can tell when we have read the available input. */ input_signal_count++; - if (numchars <= 0) - abort (); - /* Don't poll for events to process (specifically updateEvt) if window update currently already in progress. A call to redisplay (in do_window_update) can be preempted by another call to @@ -7644,7 +8061,9 @@ XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) event to nil because keyboard.c protects incompletely processed event from being garbage collected by placing them in the kbd_buffer_gcpro vector. */ - bufp->arg = Qnil; + EVENT_INIT (inev); + inev.kind = NO_EVENT; + inev.arg = Qnil; event_mask = everyEvent; if (NILP (Fboundp (Qmac_ready_for_drag_n_drop))) @@ -7682,18 +8101,17 @@ XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) GetEventParameter(eventRef, kEventParamMouseLocation, typeQDPoint, NULL, sizeof (Point), NULL, &point); - bufp->kind = WHEEL_EVENT; - bufp->code = 0; - bufp->modifiers = (mac_event_to_emacs_modifiers(eventRef) - | ((delta < 0) ? down_modifier - : up_modifier)); + inev.kind = WHEEL_EVENT; + inev.code = 0; + inev.modifiers = (mac_event_to_emacs_modifiers(eventRef) + | ((delta < 0) ? down_modifier + : up_modifier)); SetPort (GetWindowPort (window_ptr)); GlobalToLocal (&point); - XSETINT (bufp->x, point.h); - XSETINT (bufp->y, point.v); - XSETFRAME (bufp->frame_or_window, mwp->mFP); - bufp->timestamp = EventTimeToTicks (GetEventTime (eventRef))*(1000/60); - count++; + XSETINT (inev.x, point.h); + XSETINT (inev.y, point.v); + XSETFRAME (inev.frame_or_window, mwp->mFP); + inev.timestamp = EventTimeToTicks (GetEventTime (eventRef))*(1000/60); } else SendEventToEventTarget (eventRef, GetEventDispatcherTarget ()); @@ -7742,28 +8160,27 @@ XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) GlobalToLocal (&mouse_loc); #if USE_CARBON_EVENTS - bufp->code = mac_get_mouse_btn (eventRef); + inev.code = mac_get_mouse_btn (eventRef); #else - bufp->code = 0; /* only one mouse button */ + inev.code = mac_get_emulate_btn (er.modifiers); #endif - bufp->kind = SCROLL_BAR_CLICK_EVENT; - bufp->frame_or_window = tracked_scroll_bar->window; - bufp->part = scroll_bar_handle; + inev.kind = SCROLL_BAR_CLICK_EVENT; + inev.frame_or_window = tracked_scroll_bar->window; + inev.part = scroll_bar_handle; #if USE_CARBON_EVENTS - bufp->modifiers = mac_event_to_emacs_modifiers (eventRef); + inev.modifiers = mac_event_to_emacs_modifiers (eventRef); #else - bufp->modifiers = mac_to_emacs_modifiers (er.modifiers); + inev.modifiers = mac_to_emacs_modifiers (er.modifiers); #endif - bufp->modifiers |= up_modifier; - bufp->timestamp = er.when * (1000 / 60); + inev.modifiers |= up_modifier; + inev.timestamp = er.when * (1000 / 60); /* ticks to milliseconds */ - XSETINT (bufp->x, tracked_scroll_bar->left + 2); - XSETINT (bufp->y, mouse_loc.v - 24); + XSETINT (inev.x, tracked_scroll_bar->left + 2); + XSETINT (inev.y, mouse_loc.v - 24); tracked_scroll_bar->dragging = Qnil; mouse_tracking_in_progress = mouse_tracking_none; tracked_scroll_bar = NULL; - count++; break; } @@ -7772,14 +8189,14 @@ XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) switch (part_code) { case inMenuBar: - { - struct frame *f = ((mac_output *) - GetWRefCon (FrontWindow ()))->mFP; - saved_menu_event_location = er.where; - bufp->kind = MENU_BAR_ACTIVATE_EVENT; - XSETFRAME (bufp->frame_or_window, f); - count++; - } + if (er.what == mouseDown) + { + struct frame *f = ((mac_output *) + GetWRefCon (FrontWindow ()))->mFP; + saved_menu_event_location = er.where; + inev.kind = MENU_BAR_ACTIVATE_EVENT; + XSETFRAME (inev.frame_or_window, f); + } break; case inContent: @@ -7809,13 +8226,13 @@ XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) #endif #if USE_CARBON_EVENTS - bufp->code = mac_get_mouse_btn (eventRef); + inev.code = mac_get_mouse_btn (eventRef); #else - bufp->code = 0; /* only one mouse button */ + inev.code = mac_get_emulate_btn (er.modifiers); #endif - XSETINT (bufp->x, mouse_loc.h); - XSETINT (bufp->y, mouse_loc.v); - bufp->timestamp = er.when * (1000 / 60); + XSETINT (inev.x, mouse_loc.h); + XSETINT (inev.y, mouse_loc.v); + inev.timestamp = er.when * (1000 / 60); /* ticks to milliseconds */ #if TARGET_API_MAC_CARBON @@ -7827,7 +8244,7 @@ XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) struct scroll_bar *bar = (struct scroll_bar *) GetControlReference (ch); x_scroll_bar_handle_click (bar, control_part_code, &er, - bufp); + &inev); if (er.what == mouseDown && control_part_code == kControlIndicatorPart) { @@ -7843,43 +8260,61 @@ XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) } else { - bufp->kind = MOUSE_CLICK_EVENT; - XSETFRAME (bufp->frame_or_window, mwp->mFP); + Lisp_Object window; + + XSETFRAME (inev.frame_or_window, mwp->mFP); if (er.what == mouseDown) - mouse_tracking_in_progress + mouse_tracking_in_progress = mouse_tracking_mouse_movement; else - mouse_tracking_in_progress = mouse_tracking_none; - } + mouse_tracking_in_progress = mouse_tracking_none; + window = window_from_coordinates (mwp->mFP, inev.x, inev.y, 0, 0, 0, 1); + + if (EQ (window, mwp->mFP->tool_bar_window)) + { + if (er.what == mouseDown) + handle_tool_bar_click (mwp->mFP, inev.x, inev.y, 1, 0); + else + handle_tool_bar_click (mwp->mFP, inev.x, inev.y, 0, +#if USE_CARBON_EVENTS + mac_event_to_emacs_modifiers (eventRef) +#else + er.modifiers +#endif + ); + break; + } + else + inev.kind = MOUSE_CLICK_EVENT; + } #if USE_CARBON_EVENTS - bufp->modifiers = mac_event_to_emacs_modifiers (eventRef); + inev.modifiers = mac_event_to_emacs_modifiers (eventRef); #else - bufp->modifiers = mac_to_emacs_modifiers (er.modifiers); + inev.modifiers = mac_to_emacs_modifiers (er.modifiers); #endif switch (er.what) { case mouseDown: - bufp->modifiers |= down_modifier; + inev.modifiers |= down_modifier; break; case mouseUp: - bufp->modifiers |= up_modifier; + inev.modifiers |= up_modifier; break; } - - count++; } break; case inDrag: #if TARGET_API_MAC_CARBON - { - BitMap bm; - - GetQDGlobalsScreenBits (&bm); - DragWindow (window_ptr, er.where, &bm.bounds); - } + if (er.what == mouseDown) + { + BitMap bm; + + GetQDGlobalsScreenBits (&bm); + DragWindow (window_ptr, er.where, &bm.bounds); + } #else /* not TARGET_API_MAC_CARBON */ DragWindow (window_ptr, er.where, &qd.screenBits.bounds); #endif /* not TARGET_API_MAC_CARBON */ @@ -7888,17 +8323,19 @@ XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) case inGoAway: if (TrackGoAway (window_ptr, er.where)) { - bufp->kind = DELETE_WINDOW_EVENT; - XSETFRAME (bufp->frame_or_window, + inev.kind = DELETE_WINDOW_EVENT; + XSETFRAME (inev.frame_or_window, ((mac_output *) GetWRefCon (window_ptr))->mFP); - count++; } break; /* window resize handling added --ben */ case inGrow: - do_grow_window(window_ptr, &er); - break; + if (er.what == mouseDown) + { + do_grow_window(window_ptr, &er); + break; + } /* window zoom handling added --ben */ case inZoomIn: @@ -7957,8 +8394,8 @@ XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) if (keycode_to_xkeysym (keycode, &xkeysym)) { - bufp->code = 0xff00 | xkeysym; - bufp->kind = NON_ASCII_KEYSTROKE_EVENT; + inev.code = 0xff00 | xkeysym; + inev.kind = NON_ASCII_KEYSTROKE_EVENT; } else { @@ -7977,12 +8414,12 @@ XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) int new_keycode = keycode | new_modifiers; Ptr kchr_ptr = (Ptr) GetScriptManagerVariable (smKCHRCache); unsigned long some_state = 0; - bufp->code = KeyTranslate (kchr_ptr, new_keycode, - &some_state) & 0xff; + inev.code = KeyTranslate (kchr_ptr, new_keycode, + &some_state) & 0xff; } else - bufp->code = er.message & charCodeMask; - bufp->kind = ASCII_KEYSTROKE_EVENT; + inev.code = er.message & charCodeMask; + inev.kind = ASCII_KEYSTROKE_EVENT; } } @@ -7993,7 +8430,7 @@ XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) Mac keyboard to be used to enter non-ASCII iso-latin-1 characters directly. */ if (mac_keyboard_text_encoding != kTextEncodingMacRoman - && bufp->kind == ASCII_KEYSTROKE_EVENT && bufp->code >= 128) + && inev.kind == ASCII_KEYSTROKE_EVENT && inev.code >= 128) { static TECObjectRef converter = NULL; OSStatus the_err = noErr; @@ -8022,7 +8459,7 @@ XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) if (the_err == noErr) { - unsigned char ch = bufp->code; + unsigned char ch = inev.code; ByteCount actual_input_length, actual_output_length; unsigned char outch; @@ -8033,25 +8470,23 @@ XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) if (convert_status == noErr && actual_input_length == 1 && actual_output_length == 1) - bufp->code = outch; + inev.code = outch; } } #if USE_CARBON_EVENTS - bufp->modifiers = mac_event_to_emacs_modifiers (eventRef); + inev.modifiers = mac_event_to_emacs_modifiers (eventRef); #else - bufp->modifiers = mac_to_emacs_modifiers (er.modifiers); + inev.modifiers = mac_to_emacs_modifiers (er.modifiers); #endif { mac_output *mwp = (mac_output *) GetWRefCon (FrontNonFloatingWindow ()); - XSETFRAME (bufp->frame_or_window, mwp->mFP); + XSETFRAME (inev.frame_or_window, mwp->mFP); } - bufp->timestamp = er.when * (1000 / 60); /* ticks to milliseconds */ - - count++; + inev.timestamp = er.when * (1000 / 60); /* ticks to milliseconds */ break; case kHighLevelEvent: @@ -8079,21 +8514,21 @@ XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) if (wp && is_emacs_window(wp)) f = ((mac_output *) GetWRefCon (wp))->mFP; - bufp->kind = DRAG_N_DROP_EVENT; - bufp->code = 0; - bufp->timestamp = er.when * (1000 / 60); + inev.kind = DRAG_N_DROP_EVENT; + inev.code = 0; + inev.timestamp = er.when * (1000 / 60); /* ticks to milliseconds */ #if USE_CARBON_EVENTS - bufp->modifiers = mac_event_to_emacs_modifiers (eventRef); + inev.modifiers = mac_event_to_emacs_modifiers (eventRef); #else - bufp->modifiers = mac_to_emacs_modifiers (er.modifiers); + inev.modifiers = mac_to_emacs_modifiers (er.modifiers); #endif - XSETINT (bufp->x, 0); - XSETINT (bufp->y, 0); + XSETINT (inev.x, 0); + XSETINT (inev.y, 0); XSETFRAME (frame, f); - bufp->frame_or_window = Fcons (frame, drag_and_drop_file_list); + inev.frame_or_window = Fcons (frame, drag_and_drop_file_list); /* Regardless of whether Emacs was suspended or in the foreground, ask it to redraw its entire screen. @@ -8110,8 +8545,6 @@ XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) #else /* not TARGET_API_MAC_CARBON */ InvalRect (&(wp->portRect)); #endif /* not TARGET_API_MAC_CARBON */ - - count++; } default: break; @@ -8180,8 +8613,13 @@ XTread_socket (int sd, struct input_event *bufp, int numchars, int expected) } } - UNBLOCK_INPUT; + if (inev.kind != NO_EVENT) + { + kbd_buffer_store_event_hold (&inev, hold_quit); + count++; + } + UNBLOCK_INPUT; return count; } @@ -8252,9 +8690,6 @@ NewMacWindow (FRAME_PTR fp) void make_mac_frame (struct frame *f) { - FRAME_CAN_HAVE_SCROLL_BARS (f) = 1; - FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_right; - FRAME_DESIRED_CURSOR (f) = FILLED_BOX_CURSOR; NewMacWindow(f); @@ -8303,6 +8738,9 @@ make_mac_terminal_frame (struct frame *f) FRAME_COLS (f) = 96; FRAME_LINES (f) = 4; + FRAME_CAN_HAVE_SCROLL_BARS (f) = 1; + FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_right; + make_mac_frame (f); x_make_gc (f); @@ -8326,74 +8764,6 @@ make_mac_terminal_frame (struct frame *f) Initialization ***********************************************************************/ -#ifdef USE_X_TOOLKIT -static XrmOptionDescRec emacs_options[] = { - {"-geometry", ".geometry", XrmoptionSepArg, NULL}, - {"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "yes"}, - - {"-internal-border-width", "*EmacsScreen.internalBorderWidth", - XrmoptionSepArg, NULL}, - {"-ib", "*EmacsScreen.internalBorderWidth", XrmoptionSepArg, NULL}, - - {"-T", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL}, - {"-wn", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL}, - {"-title", "*EmacsShell.title", XrmoptionSepArg, (XtPointer) NULL}, - {"-iconname", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL}, - {"-in", "*EmacsShell.iconName", XrmoptionSepArg, (XtPointer) NULL}, - {"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL}, - {"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL} -}; -#endif /* USE_X_TOOLKIT */ - -#ifdef MULTI_KBOARD -/* Test whether two display-name strings agree up to the dot that separates - the screen number from the server number. */ -static int -same_x_server (name1, name2) - char *name1, *name2; -{ - int seen_colon = 0; - unsigned char *system_name = SDATA (Vsystem_name); - int system_name_length = strlen (system_name); - int length_until_period = 0; - - while (system_name[length_until_period] != 0 - && system_name[length_until_period] != '.') - length_until_period++; - - /* Treat `unix' like an empty host name. */ - if (! strncmp (name1, "unix:", 5)) - name1 += 4; - if (! strncmp (name2, "unix:", 5)) - name2 += 4; - /* Treat this host's name like an empty host name. */ - if (! strncmp (name1, system_name, system_name_length) - && name1[system_name_length] == ':') - name1 += system_name_length; - if (! strncmp (name2, system_name, system_name_length) - && name2[system_name_length] == ':') - name2 += system_name_length; - /* Treat this host's domainless name like an empty host name. */ - if (! strncmp (name1, system_name, length_until_period) - && name1[length_until_period] == ':') - name1 += length_until_period; - if (! strncmp (name2, system_name, length_until_period) - && name2[length_until_period] == ':') - name2 += length_until_period; - - for (; *name1 != '\0' && *name1 == *name2; name1++, name2++) - { - if (*name1 == ':') - seen_colon++; - if (seen_colon && *name1 == '.') - return 1; - } - return (seen_colon - && (*name1 == '.' || *name1 == '\0') - && (*name2 == '.' || *name2 == '\0')); -} -#endif - int mac_initialized = 0; void @@ -8426,12 +8796,16 @@ mac_initialize_display_info () dpyinfo->reference_count = 0; dpyinfo->resx = 75.0; dpyinfo->resy = 75.0; - dpyinfo->n_planes = 1; - dpyinfo->n_cbits = 16; + dpyinfo->color_p = TestDeviceAttribute (main_device_handle, gdDevType); + for (dpyinfo->n_planes = 32; dpyinfo->n_planes > 0; dpyinfo->n_planes >>= 1) + if (HasDepth (main_device_handle, dpyinfo->n_planes, + gdDevType, dpyinfo->color_p)) + break; dpyinfo->height = (**main_device_handle).gdRect.bottom; dpyinfo->width = (**main_device_handle).gdRect.right; dpyinfo->grabbed = 0; dpyinfo->root_window = NULL; + dpyinfo->image_cache = make_image_cache (); dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1; dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1; @@ -8632,6 +9006,8 @@ static struct redisplay_interface x_redisplay_interface = x_get_glyph_overhangs, x_fix_overlapping_area, x_draw_fringe_bitmap, + 0, /* define_fringe_bitmap */ + 0, /* destroy_fringe_bitmap */ mac_per_char_metric, mac_encode_char, NULL, /* mac_compute_glyph_string_overhangs */ @@ -8750,6 +9126,9 @@ syms_of_macterm () Fprovide (intern ("mac-carbon"), Qnil); + staticpro (&Qreverse); + Qreverse = intern ("reverse"); + staticpro (&x_display_name_list); x_display_name_list = Qnil; @@ -8765,6 +9144,18 @@ syms_of_macterm () Qmac_ready_for_drag_n_drop = intern ("mac-ready-for-drag-n-drop"); staticpro (&Qmac_ready_for_drag_n_drop); + Qbig5 = intern ("big5"); + staticpro (&Qbig5); + + Qcn_gb = intern ("cn-gb"); + staticpro (&Qcn_gb); + + Qsjis = intern ("sjis"); + staticpro (&Qsjis); + + Qeuc_kr = intern ("euc-kr"); + staticpro (&Qeuc_kr); + DEFVAR_BOOL ("x-autoselect-window", &x_autoselect_window_p, doc: /* *Non-nil means autoselect window with mouse pointer. */); x_autoselect_window_p = 0; @@ -8794,6 +9185,17 @@ Otherwise the option key is used. */); useful for non-standard keyboard layouts. */); Vmac_reverse_ctrl_meta = Qnil; + DEFVAR_LISP ("mac-emulate-three-button-mouse", + &Vmac_emulate_three_button_mouse, + doc: /* t means that when the option-key is held down while pressing the + mouse button, the click will register as mouse-2 and while the + command-key is held down, the click will register as mouse-3. + 'reverse means that the the option-key will register for mouse-3 + and the command-key will register for mouse-2. nil means that + not emulation should be done and the modifiers should be placed + on the mouse-1 event. */); + Vmac_emulate_three_button_mouse = Qnil; + #if USE_CARBON_EVENTS DEFVAR_LISP ("mac-wheel-button-is-mouse-2", &Vmac_wheel_button_is_mouse_2, doc: /* Non-nil means that the wheel button will be treated as mouse-2 and @@ -8827,3 +9229,6 @@ command, this enables the Mac keyboard to be used to enter non-ASCII characters directly. */); mac_keyboard_text_encoding = kTextEncodingMacRoman; } + +/* arch-tag: f2259165-4454-4c04-a029-a133c8af7b5b + (do not change this comment) */ diff --git a/src/macterm.h b/src/macterm.h index 65925334623..868ce88318c 100644 --- a/src/macterm.h +++ b/src/macterm.h @@ -23,45 +23,26 @@ Boston, MA 02111-1307, USA. */ #include "macgui.h" #include "frame.h" -/* Include Carbon.h to define Cursor and Rect. */ -#ifdef HAVE_CARBON -#undef mktime -#undef DEBUG -#undef Z -#undef free -#undef malloc -#undef realloc -/* Macros max and min defined in lisp.h conflict with those in - precompiled header Carbon.h. */ -#undef max -#undef min -#undef init_process -#include <Carbon/Carbon.h> -#undef Z -#define Z (current_buffer->text->z) -#undef free -#define free unexec_free -#undef malloc -#define malloc unexec_malloc -#undef realloc -#define realloc unexec_realloc -#undef min -#define min(a, b) ((a) < (b) ? (a) : (b)) -#undef max -#define max(a, b) ((a) > (b) ? (a) : (b)) -#undef init_process -#define init_process emacs_init_process -#endif /* MAC_OSX */ - #define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b)) #define RED_FROM_ULONG(color) ((color) >> 16) #define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff) #define BLUE_FROM_ULONG(color) ((color) & 0xff) +/* Do not change `* 0x101' in the following lines to `<< 8'. If + changed, image masks in 1-bit depth will not work. */ +#define RED16_FROM_ULONG(color) (RED_FROM_ULONG(color) * 0x101) +#define GREEN16_FROM_ULONG(color) (GREEN_FROM_ULONG(color) * 0x101) +#define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG(color) * 0x101) + #define BLACK_PIX_DEFAULT(f) RGB_TO_ULONG(0,0,0) #define WHITE_PIX_DEFAULT(f) RGB_TO_ULONG(255,255,255) +/* A black pixel in a mask bitmap/pixmap means ``draw a source + pixel''. A white pixel means ``retain the current pixel''. */ +#define PIX_MASK_DRAW(f) BLACK_PIX_DEFAULT(f) +#define PIX_MASK_RETAIN(f) WHITE_PIX_DEFAULT(f) + #define FONT_WIDTH(f) ((f)->max_bounds.width) #define FONT_HEIGHT(f) ((f)->ascent + (f)->descent) #define FONT_BASE(f) ((f)->ascent) @@ -75,6 +56,7 @@ Boston, MA 02111-1307, USA. */ struct mac_bitmap_record { char *bitmap_data; + char *file; int refcount; int height, width; }; @@ -101,8 +83,13 @@ struct mac_display_info /* Number of planes on this screen. */ int n_planes; + /* Whether the screen supports color */ + int color_p; + +#if 0 /* Number of bits per pixel on this screen. */ int n_cbits; +#endif /* Dimensions of this screen. */ int height, width; @@ -253,6 +240,12 @@ extern struct x_display_info *x_display_info_for_name P_ ((Lisp_Object)); extern struct mac_display_info *mac_term_init (); +extern Lisp_Object x_list_fonts P_ ((struct frame *, Lisp_Object, int, int)); +extern struct font_info *x_get_font_info P_ ((struct frame *f, int)); +extern struct font_info *x_load_font P_ ((struct frame *, char *, int)); +extern struct font_info *x_query_font P_ ((struct frame *, char *)); +extern void x_find_ccl_program P_ ((struct font_info *)); + /* When Emacs uses a tty window, tty_display in frame.c points to an x_output struct . */ struct x_output @@ -578,6 +571,24 @@ struct frame * check_x_frame (Lisp_Object); void activate_scroll_bars (FRAME_PTR); void deactivate_scroll_bars (FRAME_PTR); +/* Defined in macterm.c. */ + +extern void x_set_window_size P_ ((struct frame *, int, int, int)); +extern void x_make_frame_visible P_ ((struct frame *)); +extern void mac_initialize P_ ((void)); +extern Pixmap XCreatePixmap P_ ((Display *, WindowPtr, unsigned int, + unsigned int, unsigned int)); +extern Pixmap XCreatePixmapFromBitmapData P_ ((Display *, WindowPtr, char *, + unsigned int, unsigned int, + unsigned long, unsigned long, + unsigned int)); +extern void XFreePixmap P_ ((Display *, Pixmap)); +extern void XSetForeground P_ ((Display *, GC, unsigned long)); +extern void mac_draw_line_to_pixmap P_ ((Display *, Pixmap, GC, int, int, + int, int)); + #define FONT_TYPE_FOR_UNIBYTE(font, ch) 0 #define FONT_TYPE_FOR_MULTIBYTE(font, ch) 0 +/* arch-tag: 6b4ca125-5bef-476d-8ee8-31ed808b7e79 + (do not change this comment) */ diff --git a/src/makefile.nt b/src/makefile.nt index e3d05846ccc..0cf08f37105 100644 --- a/src/makefile.nt +++ b/src/makefile.nt @@ -1228,3 +1228,5 @@ $(BLD)\w32bdf.obj: \ $(SRC)\w32.h \ $(SRC)\frame.h \ $(SRC)\blockinput.h + +# arch-tag: ee9a97ba-19b7-4b50-a127-aaf4efe494dc diff --git a/src/makefile.w32-in b/src/makefile.w32-in index b93b328a6e2..99a04ecc17d 100644 --- a/src/makefile.w32-in +++ b/src/makefile.w32-in @@ -120,7 +120,10 @@ OBJ1 = $(BLD)/abbrev.$(O) \ $(BLD)/coding.$(O) \ $(BLD)/category.$(O) \ $(BLD)/ccl.$(O) \ - $(BLD)/fontset.$(O) + $(BLD)/fontset.$(O) \ + $(BLD)/fringe.$(O) \ + $(BLD)/image.$(O) + WIN32OBJ = $(BLD)/w32term.$(O) \ $(BLD)/w32xfns.$(O) \ @@ -142,6 +145,7 @@ LIBS = $(TLIB0) \ $(USER32) \ $(MPR) \ $(SHELL32) \ + $(WINSPOOL) \ $(libc) # @@ -764,6 +768,21 @@ $(BLD)/frame.$(O) : \ $(SRC)/w32term.h \ $(SRC)/window.h +$(BLD)/fringe.$(O) : \ + $(SRC)/fringe.c \ + $(EMACS_ROOT)/src/s/ms-w32.h \ + $(EMACS_ROOT)/src/m/intel386.h \ + $(EMACS_ROOT)/src/config.h \ + $(SRC)/atimer.h \ + $(SRC)/blockinput.h \ + $(SRC)/buffer.h \ + $(SRC)/dispextern.h \ + $(SRC)/frame.h \ + $(SRC)/systime.h \ + $(SRC)/w32bdf.h \ + $(SRC)/w32gui.h \ + $(SRC)/window.h + $(BLD)/gmalloc.$(O) : \ $(SRC)/gmalloc.c \ $(EMACS_ROOT)/src/s/ms-w32.h \ @@ -772,6 +791,24 @@ $(BLD)/gmalloc.$(O) : \ $(EMACS_ROOT)/nt/inc/sys/param.h \ $(SRC)/getpagesize.h +$(BLD)/image.$(O): \ + $(SRC)/image.c \ + $(EMACS_ROOT)/src/s/ms-w32.h \ + $(EMACS_ROOT)/src/m/intel386.h \ + $(EMACS_ROOT)/src/config.h \ + $(SRC)/atimer.h \ + $(SRC)/blockinput.h \ + $(SRC)/dispextern.h \ + $(SRC)/epaths.h \ + $(SRC)/frame.h \ + $(SRC)/systime.h \ + $(SRC)/termhooks.h \ + $(SRC)/w32bdf.h \ + $(SRC)/w32gui.h \ + $(SRC)/w32heap.h \ + $(SRC)/w32term.h \ + $(SRC)/window.h + $(BLD)/indent.$(O) : \ $(SRC)/indent.c \ $(EMACS_ROOT)/src/s/ms-w32.h \ @@ -1500,3 +1537,5 @@ $(BLD)/w32bdf.$(O): \ $(SRC)/w32bdf.h \ $(SRC)/w32gui.h \ $(SRC)/w32term.h + +# arch-tag: 9fd7aba8-f826-4111-b3c0-497a8e7db9a0 diff --git a/src/marker.c b/src/marker.c index c20ca8d2e84..691bf6177c4 100644 --- a/src/marker.c +++ b/src/marker.c @@ -921,3 +921,6 @@ syms_of_marker () doc: /* Non-nil enables debugging checks in byte/char position conversions. */); byte_debug_flag = 0; } + +/* arch-tag: 50aa418f-cdd0-4838-b64b-94aa4b2a3b74 + (do not change this comment) */ diff --git a/src/md5.c b/src/md5.c index a27d67b04fb..c8df5616fa9 100644 --- a/src/md5.c +++ b/src/md5.c @@ -441,3 +441,6 @@ md5_process_block (buffer, len, ctx) ctx->C = C; ctx->D = D; } + +/* arch-tag: 60084f04-b434-42cb-9d2b-e91df01f4325 + (do not change this comment) */ diff --git a/src/md5.h b/src/md5.h index c4788cacabd..e1cb3dd2e5e 100644 --- a/src/md5.h +++ b/src/md5.h @@ -144,3 +144,6 @@ extern void *md5_buffer __P ((const char *buffer, size_t len, void *resblock)); #endif /* md5.h */ + +/* arch-tag: 7cd389f3-6c40-4950-999d-0b2ebd1d20d7 + (do not change this comment) */ diff --git a/src/mem-limits.h b/src/mem-limits.h index fb3dae2eb84..578cf59f12e 100644 --- a/src/mem-limits.h +++ b/src/mem-limits.h @@ -194,3 +194,6 @@ get_lim_data () #endif /* not WINDOWSNT */ #endif /* not USG */ #endif /* not NO_LIM_DATA */ + +/* arch-tag: fe39244e-e54f-4208-b7aa-02556f7841c5 + (do not change this comment) */ diff --git a/src/minibuf.c b/src/minibuf.c index 0ccab2707d4..2feac10f2b7 100644 --- a/src/minibuf.c +++ b/src/minibuf.c @@ -131,6 +131,8 @@ Lisp_Object Qminibuffer_default; Lisp_Object Qcurrent_input_method, Qactivate_input_method; +Lisp_Object Qcase_fold_search; + extern Lisp_Object Qmouse_face; extern Lisp_Object Qfield; @@ -189,7 +191,7 @@ choose_minibuf_frame_1 (ignore) DEFUN ("set-minibuffer-window", Fset_minibuffer_window, Sset_minibuffer_window, 1, 1, 0, doc: /* Specify which minibuffer window to use for the minibuffer. -This effects where the minibuffer is displayed if you put text in it +This affects where the minibuffer is displayed if you put text in it without invoking the usual minibuffer commands. */) (window) Lisp_Object window; @@ -321,7 +323,8 @@ read_minibuf_noninteractive (map, initial, prompt, backup_n, expflag, DEFUN ("minibufferp", Fminibufferp, Sminibufferp, 0, 1, 0, doc: /* Return t if BUFFER is a minibuffer. -No argument or nil as argument means use current buffer as BUFFER.*/) +No argument or nil as argument means use current buffer as BUFFER. +BUFFER can be a buffer or a buffer name. */) (buffer) Lisp_Object buffer; { @@ -404,10 +407,15 @@ minibuffer_completion_contents () return make_buffer_string (prompt_end, PT, 1); } -/* Read from the minibuffer using keymap MAP, initial contents INITIAL - (a string), putting point minus BACKUP_N bytes from the end of INITIAL, +/* Read from the minibuffer using keymap MAP and initial contents INITIAL, + putting point minus BACKUP_N bytes from the end of INITIAL, prompting with PROMPT (a string), using history list HISTVAR - with initial position HISTPOS. (BACKUP_N should be <= 0.) + with initial position HISTPOS. INITIAL should be a string or a + cons of a string and an integer. BACKUP_N should be <= 0, or + Qnil, which is equivalent to 0. If INITIAL is a cons, BACKUP_N is + ignored and replaced with an integer that puts point at one-indexed + position N in INITIAL, where N is the CDR of INITIAL, or at the + beginning of INITIAL if N <= 0. Normally return the result as a string (the text that was read), but if EXPFLAG is nonzero, read it and return the object read. @@ -419,7 +427,7 @@ minibuffer_completion_contents () If ALLOW_PROPS is nonzero, we do not throw away text properties. - if INHERIT_INPUT_METHOD is nonzeor, the minibuffer inherit the + if INHERIT_INPUT_METHOD is nonzero, the minibuffer inherits the current input method. */ static Lisp_Object @@ -441,6 +449,7 @@ read_minibuf (map, initial, prompt, backup_n, expflag, Lisp_Object mini_frame, ambient_dir, minibuffer, input_method; struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; Lisp_Object enable_multibyte; + int pos = INTEGERP (backup_n) ? XINT (backup_n) : 0; /* String to add to the history. */ Lisp_Object histstring; @@ -456,6 +465,27 @@ read_minibuf (map, initial, prompt, backup_n, expflag, cancel_hourglass (); #endif + if (!NILP (initial)) + { + if (CONSP (initial)) + { + backup_n = Fcdr (initial); + initial = Fcar (initial); + CHECK_STRING (initial); + if (!NILP (backup_n)) + { + CHECK_NUMBER (backup_n); + /* Convert to distance from end of input. */ + if (XINT (backup_n) < 1) + /* A number too small means the beginning of the string. */ + pos = - SCHARS (initial); + else + pos = XINT (backup_n) - 1 - SCHARS (initial); + } + } + else + CHECK_STRING (initial); + } val = Qnil; ambient_dir = current_buffer->directory; input_method = Qnil; @@ -482,7 +512,8 @@ read_minibuf (map, initial, prompt, backup_n, expflag, if (noninteractive) { - val = read_minibuf_noninteractive (map, initial, prompt, backup_n, + val = read_minibuf_noninteractive (map, initial, prompt, + make_number (pos), expflag, histvar, histpos, defalt, allow_props, inherit_input_method); UNGCPRO; @@ -633,8 +664,7 @@ read_minibuf (map, initial, prompt, backup_n, expflag, if (!NILP (initial)) { Finsert (1, &initial); - if (INTEGERP (backup_n)) - Fforward_char (backup_n); + Fforward_char (make_number (pos)); } clear_message (1, 1); @@ -866,62 +896,51 @@ read_minibuf_unwind (data) DEFUN ("read-from-minibuffer", Fread_from_minibuffer, Sread_from_minibuffer, 1, 7, 0, doc: /* Read a string from the minibuffer, prompting with string PROMPT. -If optional second arg INITIAL-CONTENTS is non-nil, it is a string - to be inserted into the minibuffer before reading input. - If INITIAL-CONTENTS is (STRING . POSITION), the initial input - is STRING, but point is placed at position POSITION in the minibuffer. +The optional second arg INITIAL-CONTENTS is an obsolete alternative to + DEFAULT-VALUE. It normally should be nil in new code, except when + HIST is a cons. It is discussed in more detail below. Third arg KEYMAP is a keymap to use whilst reading; if omitted or nil, the default is `minibuffer-local-map'. If fourth arg READ is non-nil, then interpret the result as a Lisp object and return that object: in other words, do `(car (read-from-string INPUT-STRING))' -Fifth arg HIST, if non-nil, specifies a history list - and optionally the initial position in the list. - It can be a symbol, which is the history list variable to use, - or it can be a cons cell (HISTVAR . HISTPOS). - In that case, HISTVAR is the history list variable to use, - and HISTPOS is the initial position (the position in the list - which INITIAL-CONTENTS corresponds to). - Positions are counted starting from 1 at the beginning of the list. +Fifth arg HIST, if non-nil, specifies a history list and optionally + the initial position in the list. It can be a symbol, which is the + history list variable to use, or it can be a cons cell + (HISTVAR . HISTPOS). In that case, HISTVAR is the history list variable + to use, and HISTPOS is the initial position for use by the minibuffer + history commands. For consistency, you should also specify that + element of the history as the value of INITIAL-CONTENTS. Positions + are counted starting from 1 at the beginning of the list. Sixth arg DEFAULT-VALUE is the default value. If non-nil, it is available - for history commands; but `read-from-minibuffer' does NOT return DEFAULT-VALUE - if the user enters empty input! It returns the empty string. + for history commands; but, unless READ is non-nil, `read-from-minibuffer' + does NOT return DEFAULT-VALUE if the user enters empty input! It returns + the empty string. Seventh arg INHERIT-INPUT-METHOD, if non-nil, means the minibuffer inherits the current input method and the setting of `enable-multibyte-characters'. If the variable `minibuffer-allow-text-properties' is non-nil, then the string which is returned includes whatever text properties - were present in the minibuffer. Otherwise the value has no text properties. */) + were present in the minibuffer. Otherwise the value has no text properties. + +The remainder of this documentation string describes the +INITIAL-CONTENTS argument in more detail. It is only relevant when +studying existing code, or when HIST is a cons. If non-nil, +INITIAL-CONTENTS is a string to be inserted into the minibuffer before +reading input. Normally, point is put at the end of that string. +However, if INITIAL-CONTENTS is \(STRING . POSITION), the initial +input is STRING, but point is placed at _one-indexed_ position +POSITION in the minibuffer. Any integer value less than or equal to +one puts point at the beginning of the string. *Note* that this +behavior differs from the way such arguments are used in `completing-read' +and some related functions, which use zero-indexing for POSITION. */) (prompt, initial_contents, keymap, read, hist, default_value, inherit_input_method) Lisp_Object prompt, initial_contents, keymap, read, hist, default_value; Lisp_Object inherit_input_method; { - int pos = 0; - Lisp_Object histvar, histpos, position, val; + Lisp_Object histvar, histpos, val; struct gcpro gcpro1; - position = Qnil; - CHECK_STRING (prompt); - if (!NILP (initial_contents)) - { - if (CONSP (initial_contents)) - { - position = Fcdr (initial_contents); - initial_contents = Fcar (initial_contents); - } - CHECK_STRING (initial_contents); - if (!NILP (position)) - { - CHECK_NUMBER (position); - /* Convert to distance from end of input. */ - if (XINT (position) < 1) - /* A number too small means the beginning of the string. */ - pos = - SCHARS (initial_contents); - else - pos = XINT (position) - 1 - SCHARS (initial_contents); - } - } - if (NILP (keymap)) keymap = Vminibuffer_local_map; else @@ -944,7 +963,7 @@ If the variable `minibuffer-allow-text-properties' is non-nil, GCPRO1 (default_value); val = read_minibuf (keymap, initial_contents, prompt, - make_number (pos), !NILP (read), + Qnil, !NILP (read), histvar, histpos, default_value, minibuffer_allow_text_properties, !NILP (inherit_input_method)); @@ -953,15 +972,15 @@ If the variable `minibuffer-allow-text-properties' is non-nil, } DEFUN ("read-minibuffer", Fread_minibuffer, Sread_minibuffer, 1, 2, 0, - doc: /* Return a Lisp object read using the minibuffer. + doc: /* Return a Lisp object read using the minibuffer, unevaluated. Prompt with PROMPT. If non-nil, optional second arg INITIAL-CONTENTS -is a string to insert in the minibuffer before reading. */) +is a string to insert in the minibuffer before reading. +\(INITIAL-CONTENTS can also be a cons of a string and an integer. Such +arguments are used as in `read-from-minibuffer') */) (prompt, initial_contents) Lisp_Object prompt, initial_contents; { CHECK_STRING (prompt); - if (!NILP (initial_contents)) - CHECK_STRING (initial_contents); return read_minibuf (Vminibuffer_local_map, initial_contents, prompt, Qnil, 1, Qminibuffer_history, make_number (0), Qnil, 0, 0); @@ -970,7 +989,9 @@ is a string to insert in the minibuffer before reading. */) DEFUN ("eval-minibuffer", Feval_minibuffer, Seval_minibuffer, 1, 2, 0, doc: /* Return value of Lisp expression read using the minibuffer. Prompt with PROMPT. If non-nil, optional second arg INITIAL-CONTENTS -is a string to insert in the minibuffer before reading. */) +is a string to insert in the minibuffer before reading. +\(INITIAL-CONTENTS can also be a cons of a string and an integer. Such +arguments are used as in `read-from-minibuffer') */) (prompt, initial_contents) Lisp_Object prompt, initial_contents; { @@ -982,6 +1003,9 @@ is a string to insert in the minibuffer before reading. */) DEFUN ("read-string", Fread_string, Sread_string, 1, 5, 0, doc: /* Read a string from the minibuffer, prompting with string PROMPT. If non-nil, second arg INITIAL-INPUT is a string to insert before reading. + This argument has been superseded by DEFAULT-VALUE and should normally + be nil in new code. It behaves as in `read-from-minibuffer'. See the + documentation string of that function for details. The third arg HISTORY, if non-nil, specifies a history list and optionally the initial position in the list. See `read-from-minibuffer' for details of HISTORY argument. @@ -1005,16 +1029,18 @@ Fifth arg INHERIT-INPUT-METHOD, if non-nil, means the minibuffer inherits DEFUN ("read-no-blanks-input", Fread_no_blanks_input, Sread_no_blanks_input, 1, 3, 0, doc: /* Read a string from the terminal, not allowing blanks. -Prompt with PROMPT, and provide INITIAL as an initial value of the input string. +Prompt with PROMPT. Whitespace terminates the input. If INITIAL is +non-nil, it should be a string, which is used as initial input, with +point positioned at the end, so that SPACE will accept the input. +\(Actually, INITIAL can also be a cons of a string and an integer. +Such values are treated as in `read-from-minibuffer', but are normally +not useful in this function.) Third arg INHERIT-INPUT-METHOD, if non-nil, means the minibuffer inherits -the current input method and the setting of `enable-multibyte-characters'. */) +the current input method and the setting of`enable-multibyte-characters'. */) (prompt, initial, inherit_input_method) Lisp_Object prompt, initial, inherit_input_method; { CHECK_STRING (prompt); - if (! NILP (initial)) - CHECK_STRING (initial); - return read_minibuf (Vminibuffer_local_ns_map, initial, prompt, Qnil, 0, Qminibuffer_history, make_number (0), Qnil, 0, !NILP (inherit_input_method)); @@ -1238,7 +1264,7 @@ is used to further constrain the set of candidates. */) && (tem = Fcompare_strings (eltstring, make_number (0), make_number (SCHARS (string)), string, make_number (0), Qnil, - completion_ignore_case ?Qt : Qnil), + completion_ignore_case ? Qt : Qnil), EQ (Qt, tem))) { /* Yes. */ @@ -1247,15 +1273,20 @@ is used to further constrain the set of candidates. */) XSETFASTINT (zero, 0); /* Ignore this element if it fails to match all the regexps. */ - for (regexps = Vcompletion_regexp_list; CONSP (regexps); - regexps = XCDR (regexps)) - { - tem = Fstring_match (XCAR (regexps), eltstring, zero); - if (NILP (tem)) - break; - } - if (CONSP (regexps)) - continue; + { + int count = SPECPDL_INDEX (); + specbind (Qcase_fold_search, completion_ignore_case ? Qt : Qnil); + for (regexps = Vcompletion_regexp_list; CONSP (regexps); + regexps = XCDR (regexps)) + { + tem = Fstring_match (XCAR (regexps), eltstring, zero); + if (NILP (tem)) + break; + } + unbind_to (count, Qnil); + if (CONSP (regexps)) + continue; + } /* Ignore this element if there is a predicate and the predicate doesn't like it. */ @@ -1493,15 +1524,20 @@ are ignored unless STRING itself starts with a space. */) XSETFASTINT (zero, 0); /* Ignore this element if it fails to match all the regexps. */ - for (regexps = Vcompletion_regexp_list; CONSP (regexps); - regexps = XCDR (regexps)) - { - tem = Fstring_match (XCAR (regexps), eltstring, zero); - if (NILP (tem)) - break; - } - if (CONSP (regexps)) - continue; + { + int count = SPECPDL_INDEX (); + specbind (Qcase_fold_search, completion_ignore_case ? Qt : Qnil); + for (regexps = Vcompletion_regexp_list; CONSP (regexps); + regexps = XCDR (regexps)) + { + tem = Fstring_match (XCAR (regexps), eltstring, zero); + if (NILP (tem)) + break; + } + unbind_to (count, Qnil); + if (CONSP (regexps)) + continue; + } /* Ignore this element if there is a predicate and the predicate doesn't like it. */ @@ -1537,7 +1573,7 @@ Lisp_Object Vminibuffer_completing_file_name; DEFUN ("completing-read", Fcompleting_read, Scompleting_read, 2, 8, 0, doc: /* Read a string in the minibuffer, with completion. PROMPT is a string to prompt with; normally it ends in a colon and a space. -TABLE is an alist whose elements' cars are strings, or an obarray. +TABLE can be an list of strings, an alist, an obarray or a hash table. TABLE can also be a function to do the completion itself. PREDICATE limits completion to a subset of TABLE. See `try-completion' and `all-completions' for more details @@ -1546,26 +1582,30 @@ See `try-completion' and `all-completions' for more details If REQUIRE-MATCH is non-nil, the user is not allowed to exit unless the input is (or completes to) an element of TABLE or is null. If it is also not t, typing RET does not exit if it does non-null completion. -If the input is null, `completing-read' returns an empty string, - regardless of the value of REQUIRE-MATCH. - -If INITIAL-INPUT is non-nil, insert it in the minibuffer initially. - If it is (STRING . POSITION), the initial input - is STRING, but point is placed POSITION characters into the string. - This feature is deprecated--it is best to pass nil for INITIAL-INPUT - and supply the default value DEF instead. The user can yank the - default value into the minibuffer easily using \\[next-history-element]. - -HIST, if non-nil, specifies a history list - and optionally the initial position in the list. - It can be a symbol, which is the history list variable to use, - or it can be a cons cell (HISTVAR . HISTPOS). - In that case, HISTVAR is the history list variable to use, - and HISTPOS is the initial position (the position in the list - which INITIAL-INPUT corresponds to). - Positions are counted starting from 1 at the beginning of the list. - The variable `history-length' controls the maximum length of a - history list. +If the input is null, `completing-read' returns DEF, or an empty string + if DEF is nil, regardless of the value of REQUIRE-MATCH. + +If INITIAL-INPUT is non-nil, insert it in the minibuffer initially, + with point positioned at the end. + If it is (STRING . POSITION), the initial input is STRING, but point + is placed at _zero-indexed_ position POSITION in STRING. (*Note* + that this is different from `read-from-minibuffer' and related + functions, which use one-indexing for POSITION.) This feature is + deprecated--it is best to pass nil for INITIAL-INPUT and supply the + default value DEF instead. The user can yank the default value into + the minibuffer easily using \\[next-history-element]. + +HIST, if non-nil, specifies a history list and optionally the initial + position in the list. It can be a symbol, which is the history list + variable to use, or it can be a cons cell (HISTVAR . HISTPOS). In + that case, HISTVAR is the history list variable to use, and HISTPOS + is the initial position (the position in the list used by the + minibuffer history commands). For consistency, you should also + specify that element of the history as the value of + INITIAL-CONTENTS. (This is the only case in which you should use + INITIAL-INPUT instead of DEF.) Positions are counted starting from + 1 at the beginning of the list. The variable `history-length' + controls the maximum length of a history list. DEF, if non-nil, is the default value. @@ -1650,7 +1690,7 @@ the values STRING, PREDICATE and `lambda'. */) (string, alist, predicate) Lisp_Object string, alist, predicate; { - Lisp_Object regexps, tem = Qnil; + Lisp_Object regexps, tail, tem = Qnil; int i = 0; CHECK_STRING (string); @@ -1676,40 +1716,83 @@ the values STRING, PREDICATE and `lambda'. */) else string = Fstring_make_multibyte (string); - tem = oblookup (Vminibuffer_completion_table, + tem = oblookup (alist, SDATA (string), SCHARS (string), SBYTES (string)); - if (!SYMBOLP (tem)) - return Qnil; } + + if (completion_ignore_case && !SYMBOLP (tem)) + { + for (i = XVECTOR (alist)->size - 1; i >= 0; i--) + { + tail = XVECTOR (alist)->contents[i]; + if (SYMBOLP (tail)) + while (1) + { + if (EQ((Fcompare_strings (string, make_number (0), Qnil, + Fsymbol_name (tail), + make_number (0) , Qnil, Qt)), + Qt)) + { + tem = tail; + break; + } + if (XSYMBOL (tail)->next == 0) + break; + XSETSYMBOL (tail, XSYMBOL (tail)->next); + } + } + } + + if (!SYMBOLP (tem)) + return Qnil; } else if (HASH_TABLE_P (alist)) { - i = hash_lookup (XHASH_TABLE (alist), string, NULL); + struct Lisp_Hash_Table *h = XHASH_TABLE (alist); + i = hash_lookup (h, string, NULL); if (i >= 0) - tem = HASH_KEY (XHASH_TABLE (alist), i); + tem = HASH_KEY (h, i); else + for (i = 0; i < HASH_TABLE_SIZE (h); ++i) + if (!NILP (HASH_HASH (h, i)) && + EQ (Fcompare_strings (string, make_number (0), Qnil, + HASH_KEY (h, i), make_number (0) , Qnil, + completion_ignore_case ? Qt : Qnil), + Qt)) + { + tem = HASH_KEY (h, i); + break; + } + if (!STRINGP (tem)) return Qnil; } else return call3 (alist, string, predicate, Qlambda); /* Reject this element if it fails to match all the regexps. */ - for (regexps = Vcompletion_regexp_list; CONSP (regexps); - regexps = XCDR (regexps)) - { - if (NILP (Fstring_match (XCAR (regexps), - SYMBOLP (tem) ? string : tem, - Qnil))) - return Qnil; - } + { + int count = SPECPDL_INDEX (); + specbind (Qcase_fold_search, completion_ignore_case ? Qt : Qnil); + for (regexps = Vcompletion_regexp_list; CONSP (regexps); + regexps = XCDR (regexps)) + { + if (NILP (Fstring_match (XCAR (regexps), + SYMBOLP (tem) ? string : tem, + Qnil))) + return unbind_to (count, Qnil); + } + unbind_to (count, Qnil); + } /* Finally, check the predicate. */ if (!NILP (predicate)) - return HASH_TABLE_P (alist) - ? call2 (predicate, tem, HASH_VALUE (XHASH_TABLE (alist), i)) - : call1 (predicate, tem); + { + return HASH_TABLE_P (alist) + ? call2 (predicate, tem, HASH_VALUE (XHASH_TABLE (alist), i)) + : call1 (predicate, tem); + } else return Qt; } @@ -2161,6 +2244,8 @@ DEFUN ("display-completion-list", Fdisplay_completion_list, Sdisplay_completion_ doc: /* Display the list of completions, COMPLETIONS, using `standard-output'. Each element may be just a symbol or string or may be a list of two strings to be printed as if concatenated. +If it is a list of two strings, the first is the actual completion +alternative, the second serves as annotation. `standard-output' must be a buffer. The actual completion alternatives, as inserted, are given `mouse-face' properties of `highlight'. @@ -2201,6 +2286,8 @@ It can find the completion buffer in `standard-output'. */) startpos = Qnil; elt = Fcar (tail); + if (SYMBOLP (elt)) + elt = SYMBOL_NAME (elt); /* Compute the length of this element. */ if (CONSP (elt)) { @@ -2512,6 +2599,9 @@ syms_of_minibuf () Qactivate_input_method = intern ("activate-input-method"); staticpro (&Qactivate_input_method); + Qcase_fold_search = intern ("case-fold-search"); + staticpro (&Qcase_fold_search); + DEFVAR_LISP ("read-buffer-function", &Vread_buffer_function, doc: /* If this is non-nil, `read-buffer' does its work by calling this function. */); Vread_buffer_function = Qnil; @@ -2546,7 +2636,8 @@ This variable makes a difference whenever the minibuffer window is active. */); DEFVAR_LISP ("minibuffer-completion-table", &Vminibuffer_completion_table, doc: /* Alist or obarray used for completion in the minibuffer. -This becomes the ALIST argument to `try-completion' and `all-completion'. +This becomes the ALIST argument to `try-completion' and `all-completions'. +The value can also be a list of strings or a hash table. The value may alternatively be a function, which is given three arguments: STRING, the current buffer contents; @@ -2593,7 +2684,12 @@ Some uses of the echo area also raise that frame (since they use it too). */); minibuffer_auto_raise = 0; DEFVAR_LISP ("completion-regexp-list", &Vcompletion_regexp_list, - doc: /* List of regexps that should restrict possible completions. */); + doc: /* List of regexps that should restrict possible completions. +The basic completion functions only consider a completion acceptable +if it matches all regular expressions in this list, with +`case-fold-search' bound to the value of `completion-ignore-case'. +See Info node `(elisp)Basic Completion', for a description of these +functions. */); Vcompletion_regexp_list = Qnil; DEFVAR_BOOL ("minibuffer-allow-text-properties", @@ -2677,3 +2773,6 @@ keys_of_minibuf () initial_define_key (Vminibuffer_local_must_match_map, Ctl ('j'), "minibuffer-complete-and-exit"); } + +/* arch-tag: 8f69b601-fba3-484c-a6dd-ceaee54a7a73 + (do not change this comment) */ diff --git a/src/mktime.c b/src/mktime.c index fa9c9911edb..cd8f0254030 100644 --- a/src/mktime.c +++ b/src/mktime.c @@ -564,3 +564,6 @@ Local Variables: compile-command: "gcc -DDEBUG -DHAVE_LIMITS_H -DSTDC_HEADERS -Wall -W -O -g mktime.c -o mktime" End: */ + +/* arch-tag: 9456752f-7ddd-47cb-8286-fa807b1355ae + (do not change this comment) */ diff --git a/src/msdos.c b/src/msdos.c index 5bf608dc6a7..c4e9197ab49 100644 --- a/src/msdos.c +++ b/src/msdos.c @@ -64,6 +64,7 @@ Boston, MA 02111-1307, USA. */ #include "commands.h" #include "blockinput.h" #include "keyboard.h" +#include "intervals.h" #include <go32.h> #include <pc.h> #include <ctype.h> @@ -412,7 +413,8 @@ static unsigned short screen_virtual_offset = 0; /* A flag to control how to display unibyte 8-bit characters. */ extern int unibyte_display_via_language_environment; -Lisp_Object Qbar, Qhbar; +extern Lisp_Object Qcursor_type; +extern Lisp_Object Qbar, Qhbar; /* The screen colors of the current frame, which serve as the default colors for newly-created frames. */ @@ -1327,7 +1329,7 @@ show_mouse_face (struct display_info *dpyinfo, int hl) static void clear_mouse_face (struct display_info *dpyinfo) { - if (! NILP (dpyinfo->mouse_face_window)) + if (!dpyinfo->mouse_face_hidden && ! NILP (dpyinfo->mouse_face_window)) show_mouse_face (dpyinfo, 0); dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1; @@ -1435,7 +1437,7 @@ IT_note_mode_line_highlight (struct window *w, int x, int mode_line_p) /* Find the glyph under X. */ glyph = (row->glyphs[TEXT_AREA] + x - /* Does MS-DOG really support scroll-bars?? ++KFS */ + /* in case someone implements scroll bars some day... */ - WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)); end = glyph + row->used[TEXT_AREA]; if (glyph < end @@ -1992,8 +1994,6 @@ IT_update_end (struct frame *f) FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0; } -Lisp_Object Qcursor_type; - static void IT_frame_up_to_date (struct frame *f) { @@ -3131,7 +3131,7 @@ dos_rawgetc () union REGS regs; struct display_info *dpyinfo = FRAME_X_DISPLAY_INFO (SELECTED_FRAME()); EVENT_INIT (event); - + #ifndef HAVE_X_WINDOWS /* Maybe put the cursor where it should be. */ IT_cmgoto (SELECTED_FRAME()); @@ -3342,8 +3342,8 @@ dos_rawgetc () if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)) { - dpyinfo->mouse_face_hidden = 1; clear_mouse_face (dpyinfo); + dpyinfo->mouse_face_hidden = 1; } if (code >= 0x100) @@ -5266,18 +5266,11 @@ syms_of_msdos () #ifndef HAVE_X_WINDOWS /* The following two are from xfns.c: */ - Qbar = intern ("bar"); - staticpro (&Qbar); - Qhbar = intern ("hbar"); - staticpro (&Qhbar); - Qcursor_type = intern ("cursor-type"); - staticpro (&Qcursor_type); Qreverse = intern ("reverse"); staticpro (&Qreverse); DEFVAR_LISP ("dos-unsupported-char-glyph", &Vdos_unsupported_char_glyph, doc: /* *Glyph to display instead of chars not supported by current codepage. - This variable is used only by MSDOS terminals. */); Vdos_unsupported_char_glyph = '\177'; @@ -5297,3 +5290,6 @@ nil means don't delete them until `list-processes' is run. */); } #endif /* MSDOS */ + +/* arch-tag: db404e92-52a5-475f-9eb2-1cb78dd05f30 + (do not change this comment) */ diff --git a/src/msdos.h b/src/msdos.h index 40d01a8bba6..a07979d2f6a 100644 --- a/src/msdos.h +++ b/src/msdos.h @@ -159,3 +159,6 @@ void XMenuDestroy (Display *, XMenu *); #endif /* not HAVE_X_WINDOWS */ #endif /* not EMACS_MSDOS_H */ + +/* arch-tag: ad21eeed-8fdb-4357-8007-36368a6bdbf3 + (do not change this comment) */ diff --git a/src/ndir.h b/src/ndir.h index f02dfbd6703..bcf52c902f4 100644 --- a/src/ndir.h +++ b/src/ndir.h @@ -53,3 +53,6 @@ extern void seekdir(); extern void closedir(); #define rewinddir( dirp ) seekdir( dirp, 0L ) + +/* arch-tag: aea50570-ffb7-43fd-b423-7743b10fbe6e + (do not change this comment) */ diff --git a/src/param.h b/src/param.h index 1b27b50a276..5e80bf9e548 100644 --- a/src/param.h +++ b/src/param.h @@ -1,2 +1,5 @@ /* This is so that Emacs can run on VMS... */ #define EXEC_PAGESIZE 512 + +/* arch-tag: a6daea28-33a6-4dd3-97d8-5ee1a12f09d3 + (do not change this comment) */ diff --git a/src/point.h b/src/point.h index 7bae693f2d4..0156e1baed2 100644 --- a/src/point.h +++ b/src/point.h @@ -3,3 +3,6 @@ static char point_bits[] = { 0x1f, 0x0e, 0x0e, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x0e, 0x0e, 0x1f}; + +/* arch-tag: a8dad510-7254-4964-b71e-bb6f81cce572 + (do not change this comment) */ diff --git a/src/pre-crt0.c b/src/pre-crt0.c index 67fd31cd6ac..8abc9545417 100644 --- a/src/pre-crt0.c +++ b/src/pre-crt0.c @@ -7,3 +7,6 @@ /* Create a label to appear at the beginning of data space. */ int data_start = 0; + +/* arch-tag: 2e260272-0790-495f-9362-55abd56b5c5a + (do not change this comment) */ diff --git a/src/prefix-args.c b/src/prefix-args.c index 4f5b620a2f3..eeeb1038a47 100644 --- a/src/prefix-args.c +++ b/src/prefix-args.c @@ -71,3 +71,6 @@ Echo each ARG preceded by PREFIX and a space.\n", progname); exit (0); } + +/* arch-tag: 08136d70-e5c0-49c7-bcd8-b4850233977a + (do not change this comment) */ diff --git a/src/print.c b/src/print.c index 1d4df434475..8d0a5e2bb3b 100644 --- a/src/print.c +++ b/src/print.c @@ -511,7 +511,7 @@ print_string (string, printcharfun) for (i = 0; i < size; i++) PRINTCHAR (SREF (string, i)); else - for (i = 0; i < size_byte; i++) + for (i = 0; i < size_byte; ) { /* Here, we must convert each multi-byte form to the corresponding character code before handing it to PRINTCHAR. */ @@ -758,33 +758,42 @@ A printed representation of an object is text which describes that object. */) (object, noescape) Lisp_Object object, noescape; { - PRINTDECLARE; Lisp_Object printcharfun; /* struct gcpro gcpro1, gcpro2; */ Lisp_Object save_deactivate_mark; int count = specpdl_ptr - specpdl; + struct buffer *previous; specbind (Qinhibit_modification_hooks, Qt); - /* Save and restore this--we are altering a buffer - but we don't want to deactivate the mark just for that. - No need for specbind, since errors deactivate the mark. */ - save_deactivate_mark = Vdeactivate_mark; - /* GCPRO2 (object, save_deactivate_mark); */ - abort_on_gc++; + { + PRINTDECLARE; + + /* Save and restore this--we are altering a buffer + but we don't want to deactivate the mark just for that. + No need for specbind, since errors deactivate the mark. */ + save_deactivate_mark = Vdeactivate_mark; + /* GCPRO2 (object, save_deactivate_mark); */ + abort_on_gc++; + + printcharfun = Vprin1_to_string_buffer; + PRINTPREPARE; + print (object, printcharfun, NILP (noescape)); + /* Make Vprin1_to_string_buffer be the default buffer after PRINTFINSH */ + PRINTFINISH; + } - printcharfun = Vprin1_to_string_buffer; - PRINTPREPARE; - print (object, printcharfun, NILP (noescape)); - /* Make Vprin1_to_string_buffer be the default buffer after PRINTFINSH */ - PRINTFINISH; + previous = current_buffer; set_buffer_internal (XBUFFER (Vprin1_to_string_buffer)); object = Fbuffer_string (); if (SBYTES (object) == SCHARS (object)) STRING_SET_UNIBYTE (object); + /* Note that this won't make prepare_to_modify_buffer call + ask-user-about-supersession-threat because this buffer + does not visit a file. */ Ferase_buffer (); - set_buffer_internal (old); + set_buffer_internal (previous); Vdeactivate_mark = save_deactivate_mark; /* UNGCPRO; */ @@ -902,6 +911,49 @@ to make it write to the debugging output. */) return character; } + +#if defined(GNU_LINUX) + +/* This functionality is not vitally important in general, so we rely on + non-portable ability to use stderr as lvalue. */ + +#define WITH_REDIRECT_DEBUGGING_OUTPUT 1 + +FILE *initial_stderr_stream = NULL; + +DEFUN ("redirect-debugging-output", Fredirect_debugging_output, Sredirect_debugging_output, + 1, 2, + "FDebug output file: \nP", + doc: /* Redirect debugging output (stderr stream) to file FILE. +If FILE is nil, reset target to the initial stderr stream. +Optional arg APPEND non-nil (interactively, with prefix arg) means +append to existing target file. */) + (file, append) + Lisp_Object file, append; +{ + if (initial_stderr_stream != NULL) + fclose(stderr); + stderr = initial_stderr_stream; + initial_stderr_stream = NULL; + + if (STRINGP (file)) + { + file = Fexpand_file_name (file, Qnil); + initial_stderr_stream = stderr; + stderr = fopen(SDATA (file), NILP (append) ? "w" : "a"); + if (stderr == NULL) + { + stderr = initial_stderr_stream; + initial_stderr_stream = NULL; + report_file_error ("Cannot open debugging output stream", + Fcons (file, Qnil)); + } + } + return Qnil; +} +#endif /* GNU_LINUX */ + + /* This is the interface for debugging printing. */ void @@ -914,7 +966,9 @@ debug_print (arg) DEFUN ("error-message-string", Ferror_message_string, Serror_message_string, 1, 1, 0, - doc: /* Convert an error value (ERROR-SYMBOL . DATA) to an error message. */) + doc: /* Convert an error value (ERROR-SYMBOL . DATA) to an error message. +See Info anchor `(elisp)Definition of signal' for some details on how this +error message is constructed. */) (obj) Lisp_Object obj; { @@ -1222,7 +1276,8 @@ static void print_preprocess (obj) Lisp_Object obj; { - int i, size; + int i; + EMACS_INT size; loop: if (STRINGP (obj) || CONSP (obj) || VECTORP (obj) @@ -1288,7 +1343,9 @@ print_preprocess (obj) goto loop; case Lisp_Vectorlike: - size = XVECTOR (obj)->size & PSEUDOVECTOR_SIZE_MASK; + size = XVECTOR (obj)->size; + if (size & PSEUDOVECTOR_FLAG) + size &= PSEUDOVECTOR_SIZE_MASK; for (i = 0; i < size; i++) print_preprocess (XVECTOR (obj)->contents[i]); break; @@ -1938,7 +1995,7 @@ print_object (obj, printcharfun, escapeflag) } else { - int size = XVECTOR (obj)->size; + EMACS_INT size = XVECTOR (obj)->size; if (COMPILEDP (obj)) { PRINTCHAR ('#'); @@ -2273,6 +2330,9 @@ priorities. */); defsubr (&Sterpri); defsubr (&Swrite_char); defsubr (&Sexternal_debugging_output); +#ifdef WITH_REDIRECT_DEBUGGING_OUTPUT + defsubr (&Sredirect_debugging_output); +#endif Qexternal_debugging_output = intern ("external-debugging-output"); staticpro (&Qexternal_debugging_output); @@ -2291,3 +2351,6 @@ priorities. */); defsubr (&Swith_output_to_temp_buffer); } + +/* arch-tag: bc797170-94ae-41de-86e3-75e20f8f7a39 + (do not change this comment) */ diff --git a/src/process.c b/src/process.c index 419d108b712..1e2bcc3c2ac 100644 --- a/src/process.c +++ b/src/process.c @@ -1,6 +1,6 @@ /* Asynchronous subprocess control for GNU Emacs. Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 96, 98, 1999, - 2001, 2002, 2003 Free Software Foundation, Inc. + 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -98,6 +98,17 @@ Boston, MA 02111-1307, USA. */ #include <bsdtty.h> #endif +/* Can we use SIOCGIFCONF and/or SIOCGIFADDR */ +#ifdef HAVE_SOCKETS +#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H) +/* sys/ioctl.h may have been included already */ +#ifndef SIOCGIFADDR +#include <sys/ioctl.h> +#endif +#include <net/if.h> +#endif +#endif + #ifdef IRIS #include <sys/sysmacros.h> /* for "minor" */ #endif /* not IRIS */ @@ -249,6 +260,33 @@ int update_tick; #undef DATAGRAM_SOCKETS #endif +#if !defined (ADAPTIVE_READ_BUFFERING) && !defined (NO_ADAPTIVE_READ_BUFFERING) +#ifdef EMACS_HAS_USECS +#define ADAPTIVE_READ_BUFFERING +#endif +#endif + +#ifdef ADAPTIVE_READ_BUFFERING +#define READ_OUTPUT_DELAY_INCREMENT 10000 +#define READ_OUTPUT_DELAY_MAX (READ_OUTPUT_DELAY_INCREMENT * 5) +#define READ_OUTPUT_DELAY_MAX_MAX (READ_OUTPUT_DELAY_INCREMENT * 7) + +/* Number of processes which might be delayed. */ + +static int process_output_delay_count; + +/* Non-zero if any process has non-nil process_output_skip. */ + +static int process_output_skip; + +/* Non-nil means to delay reading process output to improve buffering. + A value of t means that delay is reset after each send, any other + non-nil value does not reset the delay. */ +static Lisp_Object Vprocess_adaptive_read_buffering; +#else +#define process_output_delay_count 0 +#endif + #include "sysselect.h" @@ -562,6 +600,12 @@ make_process (name) p->status = Qrun; p->mark = Fmake_marker (); +#ifdef ADAPTIVE_READ_BUFFERING + p->adaptive_read_buffering = Qnil; + XSETFASTINT (p->read_output_delay, 0); + p->read_output_skip = Qnil; +#endif + /* If name is already in use, modify it until it is unused. */ name1 = name; @@ -955,8 +999,14 @@ It gets two arguments: the process, and a string describing the change. */) (process, sentinel) register Lisp_Object process, sentinel; { + struct Lisp_Process *p; + CHECK_PROCESS (process); - XPROCESS (process)->sentinel = sentinel; + p = XPROCESS (process); + + p->sentinel = sentinel; + if (NETCONN1_P (p)) + p->childp = Fplist_put (p->childp, QCsentinel, sentinel); return sentinel; } @@ -1485,6 +1535,10 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */) = buffer_defaults.enable_multibyte_characters; XPROCESS (proc)->command = Flist (nargs - 2, args + 2); +#ifdef ADAPTIVE_READ_BUFFERING + XPROCESS (proc)->adaptive_read_buffering = Vprocess_adaptive_read_buffering; +#endif + /* Make the process marker point into the process buffer (if any). */ if (!NILP (buffer)) set_marker_both (XPROCESS (proc)->mark, buffer, @@ -2298,233 +2352,172 @@ static struct socket_options { /* The name of this option. Should be lowercase version of option name without SO_ prefix. */ char *name; - /* Length of name. */ - int nlen; /* Option level SOL_... */ int optlevel; /* Option number SO_... */ int optnum; - enum { SOPT_UNKNOWN, SOPT_BOOL, SOPT_INT, SOPT_STR, SOPT_LINGER } opttype; + enum { SOPT_UNKNOWN, SOPT_BOOL, SOPT_INT, SOPT_IFNAME, SOPT_LINGER } opttype; + enum { OPIX_NONE=0, OPIX_MISC=1, OPIX_REUSEADDR=2 } optbit; } socket_options[] = { #ifdef SO_BINDTODEVICE - { "bindtodevice", 12, SOL_SOCKET, SO_BINDTODEVICE, SOPT_STR }, + { ":bindtodevice", SOL_SOCKET, SO_BINDTODEVICE, SOPT_IFNAME, OPIX_MISC }, #endif #ifdef SO_BROADCAST - { "broadcast", 9, SOL_SOCKET, SO_BROADCAST, SOPT_BOOL }, + { ":broadcast", SOL_SOCKET, SO_BROADCAST, SOPT_BOOL, OPIX_MISC }, #endif #ifdef SO_DONTROUTE - { "dontroute", 9, SOL_SOCKET, SO_DONTROUTE, SOPT_BOOL }, + { ":dontroute", SOL_SOCKET, SO_DONTROUTE, SOPT_BOOL, OPIX_MISC }, #endif #ifdef SO_KEEPALIVE - { "keepalive", 9, SOL_SOCKET, SO_KEEPALIVE, SOPT_BOOL }, + { ":keepalive", SOL_SOCKET, SO_KEEPALIVE, SOPT_BOOL, OPIX_MISC }, #endif #ifdef SO_LINGER - { "linger", 6, SOL_SOCKET, SO_LINGER, SOPT_LINGER }, + { ":linger", SOL_SOCKET, SO_LINGER, SOPT_LINGER, OPIX_MISC }, #endif #ifdef SO_OOBINLINE - { "oobinline", 9, SOL_SOCKET, SO_OOBINLINE, SOPT_BOOL }, + { ":oobinline", SOL_SOCKET, SO_OOBINLINE, SOPT_BOOL, OPIX_MISC }, #endif #ifdef SO_PRIORITY - { "priority", 8, SOL_SOCKET, SO_PRIORITY, SOPT_INT }, + { ":priority", SOL_SOCKET, SO_PRIORITY, SOPT_INT, OPIX_MISC }, #endif #ifdef SO_REUSEADDR - { "reuseaddr", 9, SOL_SOCKET, SO_REUSEADDR, SOPT_BOOL }, + { ":reuseaddr", SOL_SOCKET, SO_REUSEADDR, SOPT_BOOL, OPIX_REUSEADDR }, #endif - { 0, 0, 0, 0, SOPT_UNKNOWN } + { 0, 0, 0, SOPT_UNKNOWN, OPIX_NONE } }; -/* Process list of socket options OPTS on socket S. - Only check if options are supported is S < 0. - If NO_ERROR is non-zero, continue silently if an option - cannot be set. +/* Set option OPT to value VAL on socket S. - Each element specifies one option. An element is either a string - "OPTION=VALUE" or a cons (OPTION . VALUE) where OPTION is a string - or a symbol. */ + Returns (1<<socket_options[OPT].optbit) if option is known, 0 otherwise. + Signals an error if setting a known option fails. +*/ static int -set_socket_options (s, opts, no_error) +set_socket_option (s, opt, val) int s; - Lisp_Object opts; - int no_error; + Lisp_Object opt, val; { - if (!CONSP (opts)) - opts = Fcons (opts, Qnil); + char *name; + struct socket_options *sopt; + int ret = 0; - while (CONSP (opts)) - { - Lisp_Object opt; - Lisp_Object val; - char *name, *arg; - struct socket_options *sopt; - int ret = 0; - - opt = XCAR (opts); - opts = XCDR (opts); - - name = 0; - val = Qt; - if (CONSP (opt)) - { - val = XCDR (opt); - opt = XCAR (opt); - } - if (STRINGP (opt)) - name = (char *) SDATA (opt); - else if (SYMBOLP (opt)) - name = (char *) SDATA (SYMBOL_NAME (opt)); - else { - error ("Mal-formed option list"); - return 0; - } + CHECK_SYMBOL (opt); - if (strncmp (name, "no", 2) == 0) - { - val = Qnil; - name += 2; - } + name = (char *) SDATA (SYMBOL_NAME (opt)); + for (sopt = socket_options; sopt->name; sopt++) + if (strcmp (name, sopt->name) == 0) + break; - arg = 0; - for (sopt = socket_options; sopt->name; sopt++) - if (strncmp (name, sopt->name, sopt->nlen) == 0) - { - if (name[sopt->nlen] == 0) - break; - if (name[sopt->nlen] == '=') - { - arg = name + sopt->nlen + 1; - break; - } - } + switch (sopt->opttype) + { + case SOPT_BOOL: + { + int optval; + optval = NILP (val) ? 0 : 1; + ret = setsockopt (s, sopt->optlevel, sopt->optnum, + &optval, sizeof (optval)); + break; + } - switch (sopt->opttype) - { - case SOPT_BOOL: - { - int optval; - if (s < 0) - return 1; - if (arg) - optval = (*arg == '0' || *arg == 'n') ? 0 : 1; - else if (INTEGERP (val)) - optval = XINT (val) == 0 ? 0 : 1; - else - optval = NILP (val) ? 0 : 1; - ret = setsockopt (s, sopt->optlevel, sopt->optnum, - &optval, sizeof (optval)); - break; - } + case SOPT_INT: + { + int optval; + if (INTEGERP (val)) + optval = XINT (val); + else + error ("Bad option value for %s", name); + ret = setsockopt (s, sopt->optlevel, sopt->optnum, + &optval, sizeof (optval)); + break; + } - case SOPT_INT: - { - int optval; - if (arg) - optval = atoi(arg); - else if (INTEGERP (val)) - optval = XINT (val); - else - error ("Bad option argument for %s", name); - if (s < 0) - return 1; - ret = setsockopt (s, sopt->optlevel, sopt->optnum, - &optval, sizeof (optval)); - break; - } +#ifdef SO_BINDTODEVICE + case SOPT_IFNAME: + { + char devname[IFNAMSIZ+1]; - case SOPT_STR: + /* This is broken, at least in the Linux 2.4 kernel. + To unbind, the arg must be a zero integer, not the empty string. + This should work on all systems. KFS. 2003-09-23. */ + bzero (devname, sizeof devname); + if (STRINGP (val)) { - if (!arg) - { - if (NILP (val)) - arg = ""; - else if (STRINGP (val)) - arg = (char *) SDATA (val); - else if (XSYMBOL (val)) - arg = (char *) SDATA (SYMBOL_NAME (val)); - else - error ("Invalid argument to %s option", name); - } - ret = setsockopt (s, sopt->optlevel, sopt->optnum, - arg, strlen (arg)); + char *arg = (char *) SDATA (val); + int len = min (strlen (arg), IFNAMSIZ); + bcopy (arg, devname, len); } + else if (!NILP (val)) + error ("Bad option value for %s", name); + ret = setsockopt (s, sopt->optlevel, sopt->optnum, + devname, IFNAMSIZ); + break; + } +#endif #ifdef SO_LINGER - case SOPT_LINGER: - { - struct linger linger; - - linger.l_onoff = 1; - linger.l_linger = 0; - - if (s < 0) - return 1; + case SOPT_LINGER: + { + struct linger linger; - if (arg) - { - if (*arg == 'n' || *arg == 't' || *arg == 'y') - linger.l_onoff = (*arg == 'n') ? 0 : 1; - else - linger.l_linger = atoi(arg); - } - else if (INTEGERP (val)) - linger.l_linger = XINT (val); - else - linger.l_onoff = NILP (val) ? 0 : 1; - ret = setsockopt (s, sopt->optlevel, sopt->optnum, - &linger, sizeof (linger)); - break; - } + linger.l_onoff = 1; + linger.l_linger = 0; + if (INTEGERP (val)) + linger.l_linger = XINT (val); + else + linger.l_onoff = NILP (val) ? 0 : 1; + ret = setsockopt (s, sopt->optlevel, sopt->optnum, + &linger, sizeof (linger)); + break; + } #endif - default: - if (s < 0) - return 0; - if (no_error) - continue; - error ("Unsupported option: %s", name); - } - if (ret < 0 && ! no_error) - report_file_error ("Cannot set network option: %s", opt); + + default: + return 0; } - return 1; + + if (ret < 0) + report_file_error ("Cannot set network option", + Fcons (opt, Fcons (val, Qnil))); + return (1 << sopt->optbit); } -DEFUN ("set-network-process-options", - Fset_network_process_options, Sset_network_process_options, - 1, MANY, 0, - doc: /* Set one or more options for network process PROCESS. -Each option is either a string "OPT=VALUE" or a cons (OPT . VALUE). -A boolean value is false if it either zero or nil, true otherwise. - -The following options are known. Consult the relevant system manual -pages for more information. - -bindtodevice=NAME -- bind to interface NAME, or remove binding if nil. -broadcast=BOOL -- Allow send and receive of datagram broadcasts. -dontroute=BOOL -- Only send to directly connected hosts. -keepalive=BOOL -- Send keep-alive messages on network stream. -linger=BOOL or TIMEOUT -- Send queued messages before closing. -oobinline=BOOL -- Place out-of-band data in receive data stream. -priority=INT -- Set protocol defined priority for sent packets. -reuseaddr=BOOL -- Allow reusing a recently used address. - -usage: (set-network-process-options PROCESS &rest OPTIONS) */) - (nargs, args) - int nargs; - Lisp_Object *args; + +DEFUN ("set-network-process-option", + Fset_network_process_option, Sset_network_process_option, + 3, 4, 0, + doc: /* For network process PROCESS set option OPTION to value VALUE. +See `make-network-process' for a list of options and values. +If optional fourth arg NO-ERROR is non-nil, don't signal an error if +OPTION is not a supported option, return nil instead; otherwise return t. */) + (process, option, value, no_error) + Lisp_Object process, option, value; + Lisp_Object no_error; { - Lisp_Object process; - Lisp_Object opts; + int s; + struct Lisp_Process *p; - process = args[0]; CHECK_PROCESS (process); - if (nargs > 1 && XINT (XPROCESS (process)->infd) >= 0) + p = XPROCESS (process); + if (!NETCONN1_P (p)) + error ("Process is not a network process"); + + s = XINT (p->infd); + if (s < 0) + error ("Process is not running"); + + if (set_socket_option (s, option, value)) { - opts = Flist (nargs, args); - set_socket_options (XINT (XPROCESS (process)->infd), opts, 0); + p->childp = Fplist_put (p->childp, option, value); + return Qt; } - return process; + + if (NILP (no_error)) + error ("Unknown or unsupported option"); + + return Qnil; } + /* A version of request_sigio suitable for a record_unwind_protect. */ @@ -2604,10 +2597,10 @@ address data with one element per address data byte. Do not rely on this format in portable code, as it may depend on implementation defined constants, data sizes, and data structure alignment. -:coding CODING -- CODING is coding system for this process. - -:options OPTIONS -- Set the specified options for the network process. -See `set-network-process-options' for details. +:coding CODING -- If CODING is a symbol, it specifies the coding +system used for both reading and writing for this process. If CODING +is a cons (DECODING . ENCODING), DECODING is used for reading, and +ENCODING is used for writing. :nowait BOOL -- If BOOL is non-nil for a stream type client process, return without waiting for the connection to complete; instead, the @@ -2641,13 +2634,33 @@ and MESSAGE is a string. :plist PLIST -- Install PLIST as the new process' initial plist. -:server BOOL -- if BOOL is non-nil, create a server process for the +:server QLEN -- if QLEN is non-nil, create a server process for the specified FAMILY, SERVICE, and connection type (stream or datagram). -Default is a client process. +If QLEN is an integer, it is used as the max. length of the server's +pending connection queue (also known as the backlog); the default +queue length is 5. Default is to create a client process. + +The following network options can be specified for this connection: + +:broadcast BOOL -- Allow send and receive of datagram broadcasts. +:dontroute BOOL -- Only send to directly connected hosts. +:keepalive BOOL -- Send keep-alive messages on network stream. +:linger BOOL or TIMEOUT -- Send queued messages before closing. +:oobinline BOOL -- Place out-of-band data in receive data stream. +:priority INT -- Set protocol defined priority for sent packets. +:reuseaddr BOOL -- Allow reusing a recently used local address + (this is allowed by default for a server process). +:bindtodevice NAME -- bind to interface NAME. Using this may require + special privileges on some systems. + +Consult the relevant system programmer's manual pages for more +information on using these options. + + +A server process will listen for and accept connections from clients. +When a client connection is accepted, a new network process is created +for the connection with the following parameters: -A server process will listen for and accept connections from -clients. When a client connection is accepted, a new network process -is created for the connection with the following parameters: - The client's process name is constructed by concatenating the server process' NAME and a client identification string. - If the FILTER argument is non-nil, the client process will not get a @@ -2708,7 +2721,7 @@ usage: (make-network-process &rest ARGS) */) Lisp_Object name, buffer, host, service, address; Lisp_Object filter, sentinel; int is_non_blocking_client = 0; - int is_server = 0; + int is_server = 0, backlog = 5; int socktype; int family = -1; @@ -2745,6 +2758,8 @@ usage: (make-network-process &rest ARGS) */) error ("Network servers not supported"); #else is_server = 1; + if (INTEGERP (tem)) + backlog = XINT (tem); #endif } @@ -2997,6 +3012,8 @@ usage: (make-network-process &rest ARGS) */) for (lres = res; lres; lres = lres->ai_next) { + int optn, optbits; + s = socket (lres->ai_family, lres->ai_socktype, lres->ai_protocol); if (s < 0) { @@ -3030,17 +3047,27 @@ usage: (make-network-process &rest ARGS) */) /* Make us close S if quit. */ record_unwind_protect (close_file_unwind, make_number (s)); + /* Parse network options in the arg list. + We simply ignore anything which isn't a known option (including other keywords). + An error is signalled if setting a known option fails. */ + for (optn = optbits = 0; optn < nargs-1; optn += 2) + optbits |= set_socket_option (s, args[optn], args[optn+1]); + if (is_server) { /* Configure as a server socket. */ + + /* SO_REUSEADDR = 1 is default for server sockets; must specify + explicit :reuseaddr key to override this. */ #ifdef HAVE_LOCAL_SOCKETS if (family != AF_LOCAL) #endif - { - int optval = 1; - if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval)) - report_file_error ("Cannot set reuse option on server socket.", Qnil); - } + if (!(optbits & (1 << OPIX_REUSEADDR))) + { + int optval = 1; + if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval)) + report_file_error ("Cannot set reuse option on server socket", Qnil); + } if (bind (s, lres->ai_addr, lres->ai_addrlen)) report_file_error ("Cannot bind server socket", Qnil); @@ -3059,7 +3086,7 @@ usage: (make-network-process &rest ARGS) */) } #endif - if (socktype == SOCK_STREAM && listen (s, 5)) + if (socktype == SOCK_STREAM && listen (s, backlog)) report_file_error ("Cannot listen on server socket", Qnil); break; @@ -3195,10 +3222,6 @@ usage: (make-network-process &rest ARGS) */) report_file_error ("make client process failed", contact); } - tem = Fplist_get (contact, QCoptions); - if (!NILP (tem)) - set_socket_options (s, tem, 1); - #endif /* not TERM */ inch = s; @@ -3280,7 +3303,11 @@ usage: (make-network-process &rest ARGS) */) Lisp_Object args[5], val; if (!NILP (tem)) - val = XCAR (XCDR (tem)); + { + val = XCAR (XCDR (tem)); + if (CONSP (val)) + val = XCAR (val); + } else if (!NILP (Vcoding_system_for_read)) val = Vcoding_system_for_read; else if ((!NILP (buffer) && NILP (XBUFFER (buffer)->enable_multibyte_characters)) @@ -3312,7 +3339,11 @@ usage: (make-network-process &rest ARGS) */) p->decode_coding_system = val; if (!NILP (tem)) - val = XCAR (XCDR (tem)); + { + val = XCAR (XCDR (tem)); + if (CONSP (val)) + val = XCDR (val); + } else if (!NILP (Vcoding_system_for_write)) val = Vcoding_system_for_write; else if (NILP (current_buffer->enable_multibyte_characters)) @@ -3357,6 +3388,234 @@ usage: (make-network-process &rest ARGS) */) } #endif /* HAVE_SOCKETS */ + +#if defined(HAVE_SOCKETS) && defined(HAVE_NET_IF_H) && defined(HAVE_SYS_IOCTL_H) + +#ifdef SIOCGIFCONF +DEFUN ("network-interface-list", Fnetwork_interface_list, Snetwork_interface_list, 0, 0, 0, + doc: /* Return an alist of all network interfaces and their network address. +Each element is a cons, the car of which is a string containing the +interface name, and the cdr is the network address in internal +format; see the description of ADDRESS in `make-network-process'. */) + () +{ + struct ifconf ifconf; + struct ifreq *ifreqs = NULL; + int ifaces = 0; + int buf_size, s; + Lisp_Object res; + + s = socket (AF_INET, SOCK_STREAM, 0); + if (s < 0) + return Qnil; + + again: + ifaces += 25; + buf_size = ifaces * sizeof(ifreqs[0]); + ifreqs = (struct ifreq *)xrealloc(ifreqs, buf_size); + if (!ifreqs) + { + close (s); + return Qnil; + } + + ifconf.ifc_len = buf_size; + ifconf.ifc_req = ifreqs; + if (ioctl (s, SIOCGIFCONF, &ifconf)) + { + close (s); + return Qnil; + } + + if (ifconf.ifc_len == buf_size) + goto again; + + close (s); + ifaces = ifconf.ifc_len / sizeof (ifreqs[0]); + + res = Qnil; + while (--ifaces >= 0) + { + struct ifreq *ifq = &ifreqs[ifaces]; + char namebuf[sizeof (ifq->ifr_name) + 1]; + if (ifq->ifr_addr.sa_family != AF_INET) + continue; + bcopy (ifq->ifr_name, namebuf, sizeof (ifq->ifr_name)); + namebuf[sizeof (ifq->ifr_name)] = 0; + res = Fcons (Fcons (build_string (namebuf), + conv_sockaddr_to_lisp (&ifq->ifr_addr, + sizeof (struct sockaddr))), + res); + } + + return res; +} +#endif /* SIOCGIFCONF */ + +#if defined(SIOCGIFADDR) || defined(SIOCGIFHWADDR) || defined(SIOCGIFFLAGS) + +struct ifflag_def { + int flag_bit; + char *flag_sym; +}; + +static struct ifflag_def ifflag_table[] = { +#ifdef IFF_UP + { IFF_UP, "up" }, +#endif +#ifdef IFF_BROADCAST + { IFF_BROADCAST, "broadcast" }, +#endif +#ifdef IFF_DEBUG + { IFF_DEBUG, "debug" }, +#endif +#ifdef IFF_LOOPBACK + { IFF_LOOPBACK, "loopback" }, +#endif +#ifdef IFF_POINTOPOINT + { IFF_POINTOPOINT, "pointopoint" }, +#endif +#ifdef IFF_RUNNING + { IFF_RUNNING, "running" }, +#endif +#ifdef IFF_NOARP + { IFF_NOARP, "noarp" }, +#endif +#ifdef IFF_PROMISC + { IFF_PROMISC, "promisc" }, +#endif +#ifdef IFF_NOTRAILERS + { IFF_NOTRAILERS, "notrailers" }, +#endif +#ifdef IFF_ALLMULTI + { IFF_ALLMULTI, "allmulti" }, +#endif +#ifdef IFF_MASTER + { IFF_MASTER, "master" }, +#endif +#ifdef IFF_SLAVE + { IFF_SLAVE, "slave" }, +#endif +#ifdef IFF_MULTICAST + { IFF_MULTICAST, "multicast" }, +#endif +#ifdef IFF_PORTSEL + { IFF_PORTSEL, "portsel" }, +#endif +#ifdef IFF_AUTOMEDIA + { IFF_AUTOMEDIA, "automedia" }, +#endif +#ifdef IFF_DYNAMIC + { IFF_DYNAMIC, "dynamic" }, +#endif + { 0, 0 } +}; + +DEFUN ("network-interface-info", Fnetwork_interface_info, Snetwork_interface_info, 1, 1, 0, + doc: /* Return information about network interface named IFNAME. +The return value is a list (ADDR BCAST NETMASK HWADDR FLAGS), +where ADDR is the layer 3 address, BCAST is the layer 3 broadcast address, +NETMASK is the layer 3 network mask, HWADDR is the layer 2 addres, and +FLAGS is the current flags of the interface. */) + (ifname) + Lisp_Object ifname; +{ + struct ifreq rq; + Lisp_Object res = Qnil; + Lisp_Object elt; + int s; + int any = 0; + + CHECK_STRING (ifname); + + bzero (rq.ifr_name, sizeof rq.ifr_name); + strncpy (rq.ifr_name, SDATA (ifname), sizeof (rq.ifr_name)); + + s = socket (AF_INET, SOCK_STREAM, 0); + if (s < 0) + return Qnil; + + elt = Qnil; +#if defined(SIOCGIFFLAGS) && defined(HAVE_STRUCT_IFREQ_IFR_FLAGS) + if (ioctl (s, SIOCGIFFLAGS, &rq) == 0) + { + int flags = rq.ifr_flags; + struct ifflag_def *fp; + int fnum; + + any++; + for (fp = ifflag_table; flags != 0 && fp; fp++) + { + if (flags & fp->flag_bit) + { + elt = Fcons (intern (fp->flag_sym), elt); + flags -= fp->flag_bit; + } + } + for (fnum = 0; flags && fnum < 32; fnum++) + { + if (flags & (1 << fnum)) + { + elt = Fcons (make_number (fnum), elt); + } + } + } +#endif + res = Fcons (elt, res); + + elt = Qnil; +#if defined(SIOCGIFHWADDR) && defined(HAVE_STRUCT_IFREQ_IFR_HWADDR) + if (ioctl (s, SIOCGIFHWADDR, &rq) == 0) + { + Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil); + register struct Lisp_Vector *p = XVECTOR (hwaddr); + int n; + + any++; + for (n = 0; n < 6; n++) + p->contents[n] = make_number (((unsigned char *)&rq.ifr_hwaddr.sa_data[0])[n]); + elt = Fcons (make_number (rq.ifr_hwaddr.sa_family), hwaddr); + } +#endif + res = Fcons (elt, res); + + elt = Qnil; +#if defined(SIOCGIFNETMASK) && defined(ifr_netmask) + if (ioctl (s, SIOCGIFNETMASK, &rq) == 0) + { + any++; + elt = conv_sockaddr_to_lisp (&rq.ifr_netmask, sizeof (rq.ifr_netmask)); + } +#endif + res = Fcons (elt, res); + + elt = Qnil; +#if defined(SIOCGIFBRDADDR) && defined(HAVE_STRUCT_IFREQ_IFR_BROADADDR) + if (ioctl (s, SIOCGIFBRDADDR, &rq) == 0) + { + any++; + elt = conv_sockaddr_to_lisp (&rq.ifr_broadaddr, sizeof (rq.ifr_broadaddr)); + } +#endif + res = Fcons (elt, res); + + elt = Qnil; +#if defined(SIOCGIFADDR) && defined(HAVE_STRUCT_IFREQ_IFR_ADDR) + if (ioctl (s, SIOCGIFADDR, &rq) == 0) + { + any++; + elt = conv_sockaddr_to_lisp (&rq.ifr_addr, sizeof (rq.ifr_addr)); + } +#endif + res = Fcons (elt, res); + + close (s); + + return any ? res : Qnil; +} +#endif +#endif /* HAVE_SOCKETS */ + void deactivate_process (proc) Lisp_Object proc; @@ -3367,6 +3626,16 @@ deactivate_process (proc) inchannel = XINT (p->infd); outchannel = XINT (p->outfd); +#ifdef ADAPTIVE_READ_BUFFERING + if (XINT (p->read_output_delay) > 0) + { + if (--process_output_delay_count < 0) + process_output_delay_count = 0; + XSETINT (p->read_output_delay, 0); + p->read_output_skip = Qnil; + } +#endif + if (inchannel >= 0) { /* Beware SIGCHLD hereabouts. */ @@ -3752,7 +4021,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display) register int channel, nfds; static SELECT_TYPE Available; static SELECT_TYPE Connecting; - int check_connect, no_avail; + int check_connect, check_delay, no_avail; int xerrno; Lisp_Object proc; EMACS_TIME timeout, end_time; @@ -3812,6 +4081,10 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display) Otherwise, do pending quit if requested. */ if (XINT (read_kbd) >= 0) QUIT; +#ifdef SYNC_INPUT + else if (interrupt_input_pending) + handle_async_input (); +#endif /* Exit now if the cell we're waiting for became non-nil. */ if (! NILP (wait_for_cell) && ! NILP (XCAR (wait_for_cell))) @@ -3981,7 +4254,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display) if (!NILP (wait_for_cell)) { Available = non_process_wait_mask; - check_connect = 0; + check_connect = check_delay = 0; } else { @@ -3990,6 +4263,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display) else Available = input_wait_mask; check_connect = (num_pending_connects > 0); + check_delay = wait_channel >= 0 ? 0 : process_output_delay_count; } /* If frame size has changed or the window is newly mapped, @@ -4015,6 +4289,34 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display) { if (check_connect) Connecting = connect_wait_mask; + +#ifdef ADAPTIVE_READ_BUFFERING + if (process_output_skip && check_delay > 0) + { + int usecs = EMACS_USECS (timeout); + if (EMACS_SECS (timeout) > 0 || usecs > READ_OUTPUT_DELAY_MAX) + usecs = READ_OUTPUT_DELAY_MAX; + for (channel = 0; check_delay > 0 && channel <= max_process_desc; channel++) + { + proc = chan_process[channel]; + if (NILP (proc)) + continue; + if (XINT (XPROCESS (proc)->read_output_delay) > 0) + { + check_delay--; + if (NILP (XPROCESS (proc)->read_output_skip)) + continue; + FD_CLR (channel, &Available); + XPROCESS (proc)->read_output_skip = Qnil; + if (XINT (XPROCESS (proc)->read_output_delay) < usecs) + usecs = XINT (XPROCESS (proc)->read_output_delay); + } + } + EMACS_SET_SECS_USECS (timeout, 0, usecs); + process_output_skip = 0; + } +#endif + nfds = select (max (max_process_desc, max_keyboard_desc) + 1, &Available, (check_connect ? &Connecting : (SELECT_TYPE *)0), @@ -4468,7 +4770,36 @@ read_process_output (proc, channel) else #endif if (proc_buffered_char[channel] < 0) - nbytes = emacs_read (channel, chars + carryover, readmax - carryover); + { + nbytes = emacs_read (channel, chars + carryover, readmax - carryover); +#ifdef ADAPTIVE_READ_BUFFERING + if (!NILP (p->adaptive_read_buffering)) + { + int delay = XINT (p->read_output_delay); + if (nbytes < 256) + { + if (delay < READ_OUTPUT_DELAY_MAX_MAX) + { + if (delay == 0) + process_output_delay_count++; + delay += READ_OUTPUT_DELAY_INCREMENT * 2; + } + } + else if (delay > 0 && (nbytes == readmax - carryover)) + { + delay -= READ_OUTPUT_DELAY_INCREMENT; + if (delay == 0) + process_output_delay_count--; + } + XSETINT (p->read_output_delay, delay); + if (delay) + { + p->read_output_skip = Qt; + process_output_skip = 1; + } + } +#endif + } else { chars[carryover] = proc_buffered_char[channel]; @@ -4774,6 +5105,7 @@ send_process (proc, buf, len, object) volatile Lisp_Object object; { /* Use volatile to protect variables from being clobbered by longjmp. */ + struct Lisp_Process *p = XPROCESS (proc); int rv; struct coding_system *coding; struct gcpro gcpro1; @@ -4781,20 +5113,17 @@ send_process (proc, buf, len, object) GCPRO1 (object); #ifdef VMS - struct Lisp_Process *p = XPROCESS (proc); VMS_PROC_STUFF *vs, *get_vms_process_pointer(); #endif /* VMS */ - if (! NILP (XPROCESS (proc)->raw_status_low)) - update_status (XPROCESS (proc)); - if (! EQ (XPROCESS (proc)->status, Qrun)) - error ("Process %s not running", - SDATA (XPROCESS (proc)->name)); - if (XINT (XPROCESS (proc)->outfd) < 0) - error ("Output file descriptor of %s is closed", - SDATA (XPROCESS (proc)->name)); + if (! NILP (p->raw_status_low)) + update_status (p); + if (! EQ (p->status, Qrun)) + error ("Process %s not running", SDATA (p->name)); + if (XINT (p->outfd) < 0) + error ("Output file descriptor of %s is closed", SDATA (p->name)); - coding = proc_encode_coding_system[XINT (XPROCESS (proc)->outfd)]; + coding = proc_encode_coding_system[XINT (p->outfd)]; Vlast_coding_system_used = CODING_ID_NAME (coding->id); if ((STRINGP (object) && STRING_MULTIBYTE (object)) @@ -4802,14 +5131,12 @@ send_process (proc, buf, len, object) && !NILP (XBUFFER (object)->enable_multibyte_characters)) || EQ (object, Qt)) { - if (!EQ (Vlast_coding_system_used, - XPROCESS (proc)->encode_coding_system)) + if (!EQ (Vlast_coding_system_used, p->encode_coding_system)) /* The coding system for encoding was changed to raw-text because we sent a unibyte text previously. Now we are sending a multibyte text, thus we must encode it by the - original coding system specified for the current - process. */ - setup_coding_system (XPROCESS (proc)->encode_coding_system, coding); + original coding system specified for the current process. */ + setup_coding_system (p->encode_coding_system, coding); coding->src_multibyte = 1; } else @@ -4880,8 +5207,7 @@ send_process (proc, buf, len, object) if (pty_max_bytes == 0) { #if defined (HAVE_FPATHCONF) && defined (_PC_MAX_CANON) - pty_max_bytes = fpathconf (XFASTINT (XPROCESS (proc)->outfd), - _PC_MAX_CANON); + pty_max_bytes = fpathconf (XFASTINT (p->outfd), _PC_MAX_CANON); if (pty_max_bytes < 0) pty_max_bytes = 250; #else @@ -4904,7 +5230,7 @@ send_process (proc, buf, len, object) /* Decide how much data we can send in one batch. Long lines need to be split into multiple batches. */ - if (!NILP (XPROCESS (proc)->pty_flag)) + if (!NILP (p->pty_flag)) { /* Starting this at zero is always correct when not the first iteration because the previous iteration ended by sending C-d. @@ -4933,7 +5259,7 @@ send_process (proc, buf, len, object) /* Send this batch, using one or more write calls. */ while (this > 0) { - int outfd = XINT (XPROCESS (proc)->outfd); + int outfd = XINT (p->outfd); old_sigpipe = (SIGTYPE (*) ()) signal (SIGPIPE, send_process_trap); #ifdef DATAGRAM_SOCKETS if (DATAGRAM_CHAN_P (outfd)) @@ -4946,7 +5272,18 @@ send_process (proc, buf, len, object) } else #endif - rv = emacs_write (outfd, (char *) buf, this); + { + rv = emacs_write (outfd, (char *) buf, this); +#ifdef ADAPTIVE_READ_BUFFERING + if (XINT (p->read_output_delay) > 0 + && EQ (p->adaptive_read_buffering, Qt)) + { + XSETFASTINT (p->read_output_delay, 0); + process_output_delay_count--; + p->read_output_skip = Qnil; + } +#endif + } signal (SIGPIPE, old_sigpipe); if (rv < 0) @@ -4987,8 +5324,7 @@ send_process (proc, buf, len, object) if (errno == EAGAIN) { int flags = FWRITE; - ioctl (XINT (XPROCESS (proc)->outfd), TIOCFLUSH, - &flags); + ioctl (XINT (p->outfd), TIOCFLUSH, &flags); } #endif /* BROKEN_PTY_READ_AFTER_EAGAIN */ @@ -5033,18 +5369,17 @@ send_process (proc, buf, len, object) { #ifndef VMS proc = process_sent_to; + p = XPROCESS (proc); #endif - XPROCESS (proc)->raw_status_low = Qnil; - XPROCESS (proc)->raw_status_high = Qnil; - XPROCESS (proc)->status = Fcons (Qexit, Fcons (make_number (256), Qnil)); - XSETINT (XPROCESS (proc)->tick, ++process_tick); + p->raw_status_low = Qnil; + p->raw_status_high = Qnil; + p->status = Fcons (Qexit, Fcons (make_number (256), Qnil)); + XSETINT (p->tick, ++process_tick); deactivate_process (proc); #ifdef VMS - error ("Error writing to process %s; closed it", - SDATA (XPROCESS (proc)->name)); + error ("Error writing to process %s; closed it", SDATA (p->name)); #else - error ("SIGPIPE raised on process %s; closed it", - SDATA (XPROCESS (proc)->name)); + error ("SIGPIPE raised on process %s; closed it", SDATA (p->name)); #endif } @@ -5758,7 +6093,10 @@ kill_buffer_processes (buffer) queued and the signal-catching function will be continually reentered until the queue is empty". Invoking signal() causes the kernel to reexamine the SIGCLD queue. Fred Fish, UniSoft Systems - Inc. */ + Inc. + + ** Malloc WARNING: This should never call malloc either directly or + indirectly; if it does, that is a bug */ SIGTYPE sigchld_handler (signo) @@ -5876,18 +6214,7 @@ sigchld_handler (signo) if (WIFEXITED (w)) synch_process_retcode = WRETCODE (w); else if (WIFSIGNALED (w)) - { - int code = WTERMSIG (w); - char *signame; - - synchronize_system_messages_locale (); - signame = strsignal (code); - - if (signame == 0) - signame = "unknown"; - - synch_process_death = signame; - } + synch_process_termsig = WTERMSIG (w); /* Tell wait_reading_process_input that it needs to wake up and look around. */ @@ -6281,6 +6608,11 @@ init_process () FD_ZERO (&non_process_wait_mask); max_process_desc = 0; +#ifdef ADAPTIVE_READ_BUFFERING + process_output_delay_count = 0; + process_output_skip = 0; +#endif + FD_SET (0, &input_wait_mask); Vprocess_alist = Qnil; @@ -6298,6 +6630,8 @@ init_process () #ifdef HAVE_SOCKETS { Lisp_Object subfeatures = Qnil; + struct socket_options *sopt; + #define ADD_SUBFEATURE(key, val) \ subfeatures = Fcons (Fcons (key, Fcons (val, Qnil)), subfeatures) @@ -6316,30 +6650,10 @@ init_process () #if !defined(TERM) && (defined(O_NONBLOCK) || defined(O_NDELAY)) ADD_SUBFEATURE (QCserver, Qt); #endif -#ifdef SO_BINDTODEVICE - ADD_SUBFEATURE (QCoptions, intern ("bindtodevice")); -#endif -#ifdef SO_BROADCAST - ADD_SUBFEATURE (QCoptions, intern ("broadcast")); -#endif -#ifdef SO_DONTROUTE - ADD_SUBFEATURE (QCoptions, intern ("dontroute")); -#endif -#ifdef SO_KEEPALIVE - ADD_SUBFEATURE (QCoptions, intern ("keepalive")); -#endif -#ifdef SO_LINGER - ADD_SUBFEATURE (QCoptions, intern ("linger")); -#endif -#ifdef SO_OOBINLINE - ADD_SUBFEATURE (QCoptions, intern ("oobinline")); -#endif -#ifdef SO_PRIORITY - ADD_SUBFEATURE (QCoptions, intern ("priority")); -#endif -#ifdef SO_REUSEADDR - ADD_SUBFEATURE (QCoptions, intern ("reuseaddr")); -#endif + + for (sopt = socket_options; sopt->name; sopt++) + subfeatures = Fcons (intern (sopt->name), subfeatures); + Fprovide (intern ("make-network-process"), subfeatures); } #endif /* HAVE_SOCKETS */ @@ -6432,6 +6746,20 @@ then a pipe is used in any case. The value takes effect when `start-process' is called. */); Vprocess_connection_type = Qt; +#ifdef ADAPTIVE_READ_BUFFERING + DEFVAR_LISP ("process-adaptive-read-buffering", &Vprocess_adaptive_read_buffering, + doc: /* If non-nil, improve receive buffering by delaying after short reads. +On some systems, when emacs reads the output from a subprocess, the output data +is read in very small blocks, potentially resulting in very poor performance. +This behaviour can be remedied to some extent by setting this variable to a +non-nil value, as it will automatically delay reading from such processes, to +allowing them to produce more output before emacs tries to read it. +If the value is t, the delay is reset after each write to the process; any other +non-nil value means that the delay is not reset on write. +The variable takes effect when `start-process' is called. */); + Vprocess_adaptive_read_buffering = Qt; +#endif + defsubr (&Sprocessp); defsubr (&Sget_process); defsubr (&Sget_buffer_process); @@ -6461,10 +6789,18 @@ The value takes effect when `start-process' is called. */); defsubr (&Sprocess_list); defsubr (&Sstart_process); #ifdef HAVE_SOCKETS - defsubr (&Sset_network_process_options); + defsubr (&Sset_network_process_option); defsubr (&Smake_network_process); defsubr (&Sformat_network_address); #endif /* HAVE_SOCKETS */ +#if defined(HAVE_SOCKETS) && defined(HAVE_NET_IF_H) && defined(HAVE_SYS_IOCTL_H) +#ifdef SIOCGIFCONF + defsubr (&Snetwork_interface_list); +#endif +#if defined(SIOCGIFADDR) || defined(SIOCGIFHWADDR) || defined(SIOCGIFFLAGS) + defsubr (&Snetwork_interface_info); +#endif +#endif /* HAVE_SOCKETS ... */ #ifdef DATAGRAM_SOCKETS defsubr (&Sprocess_datagram_address); defsubr (&Sset_process_datagram_address); @@ -6796,3 +7132,6 @@ syms_of_process () #endif /* not subprocesses */ + +/* arch-tag: 3706c011-7b9a-4117-bd4f-59e7f701a4c4 + (do not change this comment) */ diff --git a/src/process.h b/src/process.h index 6ad7f7ddf5e..6e2641d6b06 100644 --- a/src/process.h +++ b/src/process.h @@ -101,6 +101,18 @@ struct Lisp_Process generated, and can be changed by the function `set-process-fileter-multibyte'. */ Lisp_Object filter_multibyte; + /* Should we delay reading output from this process. + Initialized from `Vprocess_adaptive_read_buffering'. */ + Lisp_Object adaptive_read_buffering; + /* Hysteresis to try to read process output in larger blocks. + On some systems, e.g. the Linux kernel, emacs is seen as + an interactive app also when reading process output, meaning + that process output can be read in as little as 1 byte at a + time. Value is micro-seconds to delay reading output from + this process. Range is 0 .. 50000. */ + Lisp_Object read_output_delay; + /* Skip reading this process on next read. */ + Lisp_Object read_output_skip; }; /* Every field in the preceding structure except for the first two @@ -124,6 +136,9 @@ extern int synch_process_alive; /* Nonzero => this is a string explaining death of synchronous subprocess. */ extern char *synch_process_death; +/* Nonzero => this is the signal number that terminated the subprocess. */ +extern int synch_process_termsig; + /* If synch_process_death is zero, this is exit code of synchronous subprocess. */ extern int synch_process_retcode; @@ -133,3 +148,6 @@ extern int synch_process_retcode; #ifndef NULL_DEVICE #define NULL_DEVICE "/dev/null" #endif + +/* arch-tag: dffedfc4-d7bc-4b58-a26f-c16155449c72 + (do not change this comment) */ diff --git a/src/puresize.h b/src/puresize.h index cc91da7d9f7..8088a374765 100644 --- a/src/puresize.h +++ b/src/puresize.h @@ -68,7 +68,7 @@ extern void pure_write_error P_ ((void)); /* Define PURE_P. */ -#ifdef VIRT_ADDR_VARIES +#if defined(VIRT_ADDR_VARIES) || defined(CYGWIN) /* For machines like APOLLO where text and data can go anywhere in virtual memory. */ @@ -96,3 +96,6 @@ extern char my_edata[]; #endif /* PNTR_COMPARISON_TYPE */ #endif /* VIRT_ADDRESS_VARIES */ + +/* arch-tag: fd9b0a91-a70e-4729-a75a-6bb4ca1ce14f + (do not change this comment) */ diff --git a/src/ralloc.c b/src/ralloc.c index f710cfdc2b7..75c25258a9d 100644 --- a/src/ralloc.c +++ b/src/ralloc.c @@ -1286,3 +1286,6 @@ r_alloc_init () use_relocatable_buffers = 1; } + +/* arch-tag: 6a524a15-faff-44c8-95d4-a5da6f55110f + (do not change this comment) */ diff --git a/src/region-cache.c b/src/region-cache.c index b5b5202653f..251382a5a0e 100644 --- a/src/region-cache.c +++ b/src/region-cache.c @@ -21,12 +21,12 @@ Boston, MA 02111-1307, USA. */ #include <config.h> +#include <stdio.h> + #include "lisp.h" #include "buffer.h" #include "region-cache.h" -#include <stdio.h> - /* Data structures. */ @@ -832,3 +832,6 @@ pp_cache (c) fprintf (stderr, "%d : %d\n", pos, BOUNDARY_VALUE (c, i)); } } + +/* arch-tag: 98c29f3f-2ca2-4e3a-92f0-f2249200a17d + (do not change this comment) */ diff --git a/src/region-cache.h b/src/region-cache.h index 073d26b6bf3..9c104b51a1b 100644 --- a/src/region-cache.h +++ b/src/region-cache.h @@ -110,3 +110,6 @@ extern int region_cache_backward P_ ((struct buffer *BUF, struct region_cache *CACHE, int POS, int *NEXT)); + +/* arch-tag: 70f79125-ef22-4f58-9aec-a48ca2791435 + (do not change this comment) */ diff --git a/src/s/386-ix.h b/src/s/386-ix.h index dc17281df01..33658dd65e6 100644 --- a/src/s/386-ix.h +++ b/src/s/386-ix.h @@ -13,3 +13,6 @@ /* This is said to be needed as a result of having _insque rather than insque in -loldX. This may not always be the right thing. */ #define WRONG_NAME_INSQUE + +/* arch-tag: c2fc2d64-46fd-4a87-933b-85eff622829c + (do not change this comment) */ diff --git a/src/s/386bsd.h b/src/s/386bsd.h index 427dc2003de..706fbf23acb 100644 --- a/src/s/386bsd.h +++ b/src/s/386bsd.h @@ -22,3 +22,6 @@ /* This affects a declaration in xrdb.c. */ #define DECLARE_GETPWUID_WITH_UID_T + +/* arch-tag: 8a114892-0863-4285-a4cb-3d66ba2d8e7b + (do not change this comment) */ diff --git a/src/s/aix3-1.h b/src/s/aix3-1.h index 330cbae4279..b96bf4373b3 100644 --- a/src/s/aix3-1.h +++ b/src/s/aix3-1.h @@ -213,3 +213,5 @@ Boston, MA 02111-1307, USA. */ /* For unexaix.c. */ #define ALIGN_DATA_RELOC +/* arch-tag: bfff798c-542d-4290-91f2-267394c85b7b + (do not change this comment) */ diff --git a/src/s/aix3-2-5.h b/src/s/aix3-2-5.h index 04c8ccf44ad..6c8458cc8a4 100644 --- a/src/s/aix3-2-5.h +++ b/src/s/aix3-2-5.h @@ -28,3 +28,6 @@ /* Bill Woodward <wpwood@austin.ibm.com> says: libIM *must* precede libXm, to avoid getting aixLoadIM error messages. */ #define LIB_MOTIF -lIM -lXm + +/* arch-tag: 692b3acb-5383-4cfb-93f6-378b5c48c75e + (do not change this comment) */ diff --git a/src/s/aix3-2.h b/src/s/aix3-2.h index b8e5bd6d65b..6dfbe5d751c 100644 --- a/src/s/aix3-2.h +++ b/src/s/aix3-2.h @@ -49,3 +49,6 @@ lose declaring char * rindex without this. It is just a guess which versions of AIX need this definition. */ #undef HAVE_STRING_H + +/* arch-tag: 0935754d-67e1-4697-978a-3e9976da05c3 + (do not change this comment) */ diff --git a/src/s/aix4-1.h b/src/s/aix4-1.h index e179684f3b6..21d05cb154d 100644 --- a/src/s/aix4-1.h +++ b/src/s/aix4-1.h @@ -40,3 +40,6 @@ /* Unfortunately without libXmu we cannot support EditRes. */ #define NO_EDITRES #endif + +/* arch-tag: 72d598e1-bc3e-48e0-bfd2-693917c3738e + (do not change this comment) */ diff --git a/src/s/aix4-2.h b/src/s/aix4-2.h index fbc20b24a58..66b7d322b56 100644 --- a/src/s/aix4-2.h +++ b/src/s/aix4-2.h @@ -1,3 +1,6 @@ #include "aix4-1.h" #undef ALIGN_DATA_RELOC + +/* arch-tag: 38fe75ea-6aef-42bd-8449-bc34d921a562 + (do not change this comment) */ diff --git a/src/s/aix4.h b/src/s/aix4.h index 5e1be65241e..b2ed15f75ea 100644 --- a/src/s/aix4.h +++ b/src/s/aix4.h @@ -12,3 +12,6 @@ /* Specify the type that the 3rd arg of `accept' points to. It is just a guess which versions of AIX need this definition. */ #define SOCKLEN_TYPE int + +/* arch-tag: b9471dfc-ccdc-4980-a8a1-80c7627ec6b2 + (do not change this comment) */ diff --git a/src/s/bsd386.h b/src/s/bsd386.h index 99280daf832..30833b5ff9a 100644 --- a/src/s/bsd386.h +++ b/src/s/bsd386.h @@ -43,3 +43,6 @@ #endif #define GETPGRP_NO_ARG 1 + +/* arch-tag: 867e3bb8-e9df-4763-9c82-8f4accb8209e + (do not change this comment) */ diff --git a/src/s/bsd4-1.h b/src/s/bsd4-1.h index fc797755c08..624f7090f80 100644 --- a/src/s/bsd4-1.h +++ b/src/s/bsd4-1.h @@ -127,3 +127,6 @@ Boston, MA 02111-1307, USA. */ /* Special library needed for linking for 4.1. */ #define LIBS_SYSTEM -ljobs + +/* arch-tag: de56716a-ed9b-4851-a5c5-c882efaf9931 + (do not change this comment) */ diff --git a/src/s/bsd4-2.h b/src/s/bsd4-2.h index 27ad9a5fe6e..e39a8c81948 100644 --- a/src/s/bsd4-2.h +++ b/src/s/bsd4-2.h @@ -118,3 +118,6 @@ Boston, MA 02111-1307, USA. */ /* Process groups work in the traditional BSD manner. */ #define BSD_PGRPS + +/* arch-tag: 38ca640f-549e-4726-a257-71048ab4c480 + (do not change this comment) */ diff --git a/src/s/bsd4-3.h b/src/s/bsd4-3.h index 46cb3a53528..f5db6fbb5cd 100644 --- a/src/s/bsd4-3.h +++ b/src/s/bsd4-3.h @@ -118,3 +118,5 @@ Boston, MA 02111-1307, USA. */ #define SIGNALS_VIA_CHARACTERS +/* arch-tag: 0c367245-bde3-492e-9029-3ff6898beb95 + (do not change this comment) */ diff --git a/src/s/bsdos2-1.h b/src/s/bsdos2-1.h index 7a8b6630d02..244d58f5137 100644 --- a/src/s/bsdos2-1.h +++ b/src/s/bsdos2-1.h @@ -4,3 +4,6 @@ #undef LIB_X11_LIB #define LIB_X11_LIB -L/usr/X11/lib -lX11 -lipc + +/* arch-tag: cf1ada4a-cdbf-452b-a264-ff84dd523e97 + (do not change this comment) */ diff --git a/src/s/bsdos2.h b/src/s/bsdos2.h index a6970b65491..9e1e82fd75a 100644 --- a/src/s/bsdos2.h +++ b/src/s/bsdos2.h @@ -9,3 +9,6 @@ #undef KERNEL_FILE #define KERNEL_FILE "/bsd" + +/* arch-tag: 25ce1827-1511-4305-9058-24dd2118b5b4 + (do not change this comment) */ diff --git a/src/s/bsdos3.h b/src/s/bsdos3.h index faa5f821e20..20a9704e14f 100644 --- a/src/s/bsdos3.h +++ b/src/s/bsdos3.h @@ -4,3 +4,6 @@ #undef LIBS_SYSTEM #define LIBS_SYSTEM -lkvm + +/* arch-tag: 726766f3-5a62-48bf-8e21-3b21ec6abe6f + (do not change this comment) */ diff --git a/src/s/bsdos4.h b/src/s/bsdos4.h index 6c3e498deb8..540e4a7d790 100644 --- a/src/s/bsdos4.h +++ b/src/s/bsdos4.h @@ -21,3 +21,6 @@ #define LIB_GCC #endif /* not __ELF__ */ + +/* arch-tag: 7659632a-a879-4153-bb8b-3765a1463ca1 + (do not change this comment) */ diff --git a/src/s/cxux.h b/src/s/cxux.h index c39f2413cc2..fd8b00ff2b4 100644 --- a/src/s/cxux.h +++ b/src/s/cxux.h @@ -230,3 +230,6 @@ Boston, MA 02111-1307, USA. */ Note that emacs carefully avoids static vars inside functions. */ /* #define static */ + +/* arch-tag: 5febe5fe-f0b0-49cb-9280-9d5a9fa43710 + (do not change this comment) */ diff --git a/src/s/cxux7.h b/src/s/cxux7.h index 83323a98642..b9ecf45f6bb 100644 --- a/src/s/cxux7.h +++ b/src/s/cxux7.h @@ -5,3 +5,6 @@ #define USING_CX_UX_7 #include "cxux.h" + +/* arch-tag: 520cfbad-fd5c-4b3b-ace4-66e9bcd31a60 + (do not change this comment) */ diff --git a/src/s/cygwin.h b/src/s/cygwin.h index d10a7264053..38e346ac510 100644 --- a/src/s/cygwin.h +++ b/src/s/cygwin.h @@ -115,10 +115,8 @@ Boston, MA 02111-1307, USA. */ #define PENDING_OUTPUT_COUNT(FILE) ((FILE)->_p - (FILE)->_bf._base) #define GETPGRP_NO_ARG 1 #define SYSV_SYSTEM_DIR 1 -/* -lutil comes from inetutils and has pty functions in it */ -#define LIBS_SYSTEM -lutil -/* undumping is not implemented yet */ -#define CANNOT_DUMP 1 +#define LIB_STANDARD_LIBSRC +#define UNEXEC unexcw.o #define POSIX_SIGNALS 1 /* force the emacs image to start high in memory, so dll relocation can put things in low memory without causing all sorts of grief for @@ -137,10 +135,13 @@ Boston, MA 02111-1307, USA. */ /*#define HAVE_VFORK*/ /* Xaw3d causes problems -- might have been fixed by NARROWPROTO above, but I haven't tried it */ -#undef HAVE_XAW3D +/*#undef HAVE_XAW3D*/ /* vfork() interacts badly with setsid(), causing ptys to fail to change their controlling terminal */ #define vfork fork /* the end */ + +/* arch-tag: 5ae7ba00-83b0-4ab3-806a-3e845779191b + (do not change this comment) */ diff --git a/src/s/darwin.h b/src/s/darwin.h index e9faa6605ce..814de2c2c51 100644 --- a/src/s/darwin.h +++ b/src/s/darwin.h @@ -1,5 +1,5 @@ /* System description header file for Darwin (Mac OS X). - Copyright (C) 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 2001, 02, 2004 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -203,9 +203,6 @@ Boston, MA 02111-1307, USA. */ /* Fix compilation problem for regex.c. */ #define __restrict -/* Fix compilation problem for md5.c. */ -#define __attribute__(x) - /* Used in dispnew.c. Copied from freebsd.h. */ #define PENDING_OUTPUT_COUNT(FILE) ((FILE)->_p - (FILE)->_bf._base) @@ -250,7 +247,7 @@ Boston, MA 02111-1307, USA. */ page) to leave room at the end of the header for adding load commands. Needed for dumping. 0x690 is the total size of 30 segment load commands (at 56 each). */ -#define LD_SWITCH_SYSTEM_TEMACS -prebind -framework Carbon -lstdc++ -Xlinker -headerpad -Xlinker 690 +#define LD_SWITCH_SYSTEM_TEMACS -prebind -framework Carbon -framework QuickTime -lstdc++ -Xlinker -headerpad -Xlinker 690 #define C_SWITCH_SYSTEM_TEMACS -Dtemacs @@ -316,3 +313,10 @@ struct kboard; #if defined (HAVE_CARBON) && (defined (emacs) || defined (temacs)) #define select sys_select #endif + +/* Use the GC_MAKE_GCPROS_NOOPS (see lisp.h) method for marking the + stack. */ +#define GC_MARK_STACK GC_MAKE_GCPROS_NOOPS + +/* arch-tag: 481d443d-4f89-43ea-b5fb-49706d95fa41 + (do not change this comment) */ diff --git a/src/s/dgux.h b/src/s/dgux.h index 95dee6b2571..4c4a84d9996 100644 --- a/src/s/dgux.h +++ b/src/s/dgux.h @@ -349,3 +349,6 @@ extern struct sigaction act, oact; /* Process groups work in the traditional BSD manner. */ #define BSD_PGRPS + +/* arch-tag: 1b6d117d-82d2-4480-a6d0-3f7a8360f658 + (do not change this comment) */ diff --git a/src/s/dgux4.h b/src/s/dgux4.h index 188429c1aee..7a1eaf42105 100644 --- a/src/s/dgux4.h +++ b/src/s/dgux4.h @@ -137,3 +137,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define PENDING_OUTPUT_COUNT(FILE) (1) #endif /* NOT_C_CODE */ + +/* arch-tag: c7013e7b-6e2e-44f2-ba61-90b6d5e2ea45 + (do not change this comment) */ diff --git a/src/s/dgux5-4-3.h b/src/s/dgux5-4-3.h index 8091b9f88cc..3d4c4775c91 100644 --- a/src/s/dgux5-4-3.h +++ b/src/s/dgux5-4-3.h @@ -62,3 +62,6 @@ Boston, MA 02111-1307, USA. */ /* This is needed according to Ehud Karni <ehud@unix.simonwiesel.co.il> for m88k-dg-dgux5.4R3.10. */ #undef BSD_PGRPS + +/* arch-tag: c11938c9-0cb0-4652-88aa-7eb80bf1cda9 + (do not change this comment) */ diff --git a/src/s/dgux5-4r2.h b/src/s/dgux5-4r2.h index 1eaeccdf269..7121f5e18a3 100644 --- a/src/s/dgux5-4r2.h +++ b/src/s/dgux5-4r2.h @@ -45,3 +45,6 @@ Boston, MA 02111-1307, USA. */ caused trouble on DGUX 5.4.2. */ #define LIBS_SYSTEM -ldgc #endif + +/* arch-tag: a14f4043-6caa-4f01-a9b9-ae0fb0d2c96e + (do not change this comment) */ diff --git a/src/s/domain.h b/src/s/domain.h index dc57f8ff9a3..ebcdc7ea365 100644 --- a/src/s/domain.h +++ b/src/s/domain.h @@ -2,3 +2,6 @@ /* Inhibit using -X, which is the default. */ #define LD_SWITCH_SYSTEM + +/* arch-tag: 08941c4f-d0b6-4ad6-b7e3-7e7fe76c0e94 + (do not change this comment) */ diff --git a/src/s/esix.h b/src/s/esix.h index 64d0822bf5f..357e7736476 100644 --- a/src/s/esix.h +++ b/src/s/esix.h @@ -22,3 +22,6 @@ #define NO_SIOCTL_H #define NEED_PTEM_H #define BROKEN_FIONREAD + +/* arch-tag: d66e6a70-0812-437d-aa35-9b01bd474941 + (do not change this comment) */ diff --git a/src/s/esix5r4.h b/src/s/esix5r4.h index d8cf0184f3a..4240f3d7f4a 100644 --- a/src/s/esix5r4.h +++ b/src/s/esix5r4.h @@ -22,3 +22,6 @@ /* zircon!joe says this makes X windows work. */ # define BROKEN_FIONREAD #endif + +/* arch-tag: 2d314ae9-0357-4ddf-96e5-cf821071ba4b + (do not change this comment) */ diff --git a/src/s/freebsd.h b/src/s/freebsd.h index 94336835f50..dbd08f5b3be 100644 --- a/src/s/freebsd.h +++ b/src/s/freebsd.h @@ -68,6 +68,9 @@ Boston, MA 02111-1307, USA. */ #define LIBS_SYSTEM -lutil #if __FreeBSD_version < 400000 #define LIBS_TERMCAP -ltermcap +#else +#define TERMINFO +#define LIBS_TERMCAP -lncurses #endif #define SYSV_SYSTEM_DIR @@ -216,3 +219,14 @@ Boston, MA 02111-1307, USA. */ of sigblock says it is obsolete. */ #define POSIX_SIGNALS 1 + +/* The `combreloc' setting became the default, and it seems to be + incompatible with unexec. Symptom is an immediate SEGV in + XtInitializeWidget when starting Emacs under X11. */ + +#if defined __FreeBSD_version && __FreeBSD_version >= 500042 +#define LD_SWITCH_SYSTEM_TEMACS -znocombreloc +#endif + +/* arch-tag: 426529ca-b7c4-448f-b10a-d4dcdc9c78eb + (do not change this comment) */ diff --git a/src/s/gnu-linux.h b/src/s/gnu-linux.h index ac0ad0b014d..efdc2bc00ef 100644 --- a/src/s/gnu-linux.h +++ b/src/s/gnu-linux.h @@ -362,3 +362,6 @@ Boston, MA 02111-1307, USA. */ #define GC_LISP_OBJECT_ALIGNMENT 2 #endif #endif + +/* arch-tag: 6244ea2a-abd0-44ec-abec-ff3dcc9afea9 + (do not change this comment) */ diff --git a/src/s/gnu.h b/src/s/gnu.h index 807ff80378b..f7fb4899db9 100644 --- a/src/s/gnu.h +++ b/src/s/gnu.h @@ -92,3 +92,6 @@ Boston, MA 02111-1307, USA. */ ((FILE)->_IO_write_ptr - (FILE)->_IO_write_base) #endif /* !_IO_STDIO_H */ #endif /* emacs */ + +/* arch-tag: 577983d9-87a6-4922-b8f8-ff2b563714a4 + (do not change this comment) */ diff --git a/src/s/hiuxmpp.h b/src/s/hiuxmpp.h index 5175bd10bfe..04e0bd4f72c 100644 --- a/src/s/hiuxmpp.h +++ b/src/s/hiuxmpp.h @@ -42,3 +42,5 @@ #undef LDAV_SYMBOL #define LDAV_SYMBOL "avenrun" +/* arch-tag: c5422584-cd86-4e10-8089-9f604523dab7 + (do not change this comment) */ diff --git a/src/s/hiuxwe2.h b/src/s/hiuxwe2.h index 5175bd10bfe..004ddd95043 100644 --- a/src/s/hiuxwe2.h +++ b/src/s/hiuxwe2.h @@ -42,3 +42,5 @@ #undef LDAV_SYMBOL #define LDAV_SYMBOL "avenrun" +/* arch-tag: c56449e1-6d1b-4537-a596-0b08b8e4ec73 + (do not change this comment) */ diff --git a/src/s/hpux.h b/src/s/hpux.h index 9a2e7e845f8..debf6aad6d3 100644 --- a/src/s/hpux.h +++ b/src/s/hpux.h @@ -221,3 +221,6 @@ Boston, MA 02111-1307, USA. */ /* It's possible that HPUX 7 has sys/wait.h but it does not work right. */ #undef HAVE_SYS_WAIT_H #endif + +/* arch-tag: 75c1239f-fedb-4f64-8f86-7893e75699e8 + (do not change this comment) */ diff --git a/src/s/hpux10-20.h b/src/s/hpux10-20.h index 8e661188d72..a15b81a5e90 100644 --- a/src/s/hpux10-20.h +++ b/src/s/hpux10-20.h @@ -9,3 +9,5 @@ don't exist from 10.20 on (see process.c) */ #undef POLL_INTERRUPTED_SYS_CALL +/* arch-tag: 8d8dcbf1-ca9b-48a1-94be-b750de18a5c6 + (do not change this comment) */ diff --git a/src/s/hpux10.h b/src/s/hpux10.h index ba0a11ff60d..3612cfe0027 100644 --- a/src/s/hpux10.h +++ b/src/s/hpux10.h @@ -60,3 +60,6 @@ Causes "poll: interrupted system call" messages when Emacs is run in an X window (see process.c) */ #define POLL_INTERRUPTED_SYS_CALL + +/* arch-tag: 1b95d569-a3c1-4fb0-8f69-fef264c17c24 + (do not change this comment) */ diff --git a/src/s/hpux11.h b/src/s/hpux11.h index 1d49d6eedca..7bd4afb116b 100644 --- a/src/s/hpux11.h +++ b/src/s/hpux11.h @@ -13,3 +13,6 @@ /* It does work on HPUX to open the pty's tty in the parent (Emacs), then close and reopen it in the child. */ #define USG_SUBTTY_WORKS + +/* arch-tag: f5a3d780-82cd-4a9a-832e-a4031aab788b + (do not change this comment) */ diff --git a/src/s/hpux8.h b/src/s/hpux8.h index a151769fcf9..e73c630e825 100644 --- a/src/s/hpux8.h +++ b/src/s/hpux8.h @@ -69,3 +69,6 @@ /* Enable a special hack in XTread_socket. */ #define X_IO_BUG + +/* arch-tag: 25fafe5c-b26c-43ab-8144-1629d59207ee + (do not change this comment) */ diff --git a/src/s/hpux9-x11r4.h b/src/s/hpux9-x11r4.h index 7d321162eae..6a701d5a412 100644 --- a/src/s/hpux9-x11r4.h +++ b/src/s/hpux9-x11r4.h @@ -8,3 +8,5 @@ #undef LD_SWITCH_X_DEFAULT #define LD_SWITCH_X_DEFAULT -L/usr/lib/Motif1.1 +/* arch-tag: 47664d7b-23ce-43e6-acdd-044a4be08da3 + (do not change this comment) */ diff --git a/src/s/hpux9.h b/src/s/hpux9.h index d73d3b7ce8d..7562c6ae7ef 100644 --- a/src/s/hpux9.h +++ b/src/s/hpux9.h @@ -71,3 +71,5 @@ #undef HAVE_RINT +/* arch-tag: 0a5e9f05-012c-4962-a222-a7a3a7fe0ab7 + (do not change this comment) */ diff --git a/src/s/hpux9shr.h b/src/s/hpux9shr.h index 41ef98741c0..d273d2e7787 100644 --- a/src/s/hpux9shr.h +++ b/src/s/hpux9shr.h @@ -11,3 +11,6 @@ #define C_DEBUG_SWITCH #endif #endif + +/* arch-tag: 1b259627-c5f6-4260-866f-781b06d72f6b + (do not change this comment) */ diff --git a/src/s/hpux9shxr4.h b/src/s/hpux9shxr4.h index 7f59f64b777..63810273698 100644 --- a/src/s/hpux9shxr4.h +++ b/src/s/hpux9shxr4.h @@ -6,3 +6,5 @@ #undef LD_SWITCH_X_DEFAULT #define LD_SWITCH_X_DEFAULT -L/usr/lib/Motif1.1 +/* arch-tag: 7f68b8b6-c733-4e6c-81df-39d8d13fb656 + (do not change this comment) */ diff --git a/src/s/iris3-5.h b/src/s/iris3-5.h index 1b8e045ce79..51391d56e9d 100644 --- a/src/s/iris3-5.h +++ b/src/s/iris3-5.h @@ -160,3 +160,6 @@ Boston, MA 02111-1307, USA. */ /* This is how to get the device name of the tty end of a pty. */ #define PTY_TTY_NAME_SPRINTF \ sprintf (ptyname, "/dev/ttyq%d", minor (stb.st_rdev)); + +/* arch-tag: 41161051-477f-44be-bb2a-0eead3142157 + (do not change this comment) */ diff --git a/src/s/iris3-6.h b/src/s/iris3-6.h index 56e0e06fefc..50d0962e48f 100644 --- a/src/s/iris3-6.h +++ b/src/s/iris3-6.h @@ -157,3 +157,6 @@ Boston, MA 02111-1307, USA. */ /* This is how to get the device name of the tty end of a pty. */ #define PTY_TTY_NAME_SPRINTF \ sprintf (ptyname, "/dev/ttyq%d", minor (stb.st_rdev)); + +/* arch-tag: cdf2033e-a2d5-43e1-a1a2-a7243cf41a11 + (do not change this comment) */ diff --git a/src/s/irix3-3.h b/src/s/irix3-3.h index 1d02c5c3270..fad50aa20f8 100644 --- a/src/s/irix3-3.h +++ b/src/s/irix3-3.h @@ -150,3 +150,6 @@ Boston, MA 02111-1307, USA. */ /* This was formerly in LIBS_MACHINE in iris4d.h, but it is not needed for newer system versions. */ #define LIBS_SYSTEM -lsun + +/* arch-tag: cccdd761-2ae9-4e71-a33e-749681c01889 + (do not change this comment) */ diff --git a/src/s/irix4-0.h b/src/s/irix4-0.h index 4144c34d9af..215cbdc32de 100644 --- a/src/s/irix4-0.h +++ b/src/s/irix4-0.h @@ -51,3 +51,6 @@ return -1; \ strcpy (pty_name, name); \ } + +/* arch-tag: cfd7e200-a4dc-4f67-9a32-4184c10b0c57 + (do not change this comment) */ diff --git a/src/s/irix5-0.h b/src/s/irix5-0.h index 1bdd479eb9f..91017fb56d2 100644 --- a/src/s/irix5-0.h +++ b/src/s/irix5-0.h @@ -113,3 +113,6 @@ char *_getpty(); #define NARROWPROTO 1 #define USE_MMAP_FOR_BUFFERS 1 + +/* arch-tag: ad0660e0-acf8-46ae-b866-4f3df5b1101b + (do not change this comment) */ diff --git a/src/s/irix5-2.h b/src/s/irix5-2.h index a9056fae8c1..b9cca67acdf 100644 --- a/src/s/irix5-2.h +++ b/src/s/irix5-2.h @@ -16,3 +16,6 @@ for jpff@maths.bath.ac.uk. Note that irix6-0.h does not include this file, only irix5-0.h. */ #define NO_WTMP_FILE + +/* arch-tag: e2f820c1-2a3e-4cee-b5f1-6ce8ab21f439 + (do not change this comment) */ diff --git a/src/s/irix6-0.h b/src/s/irix6-0.h index ef86c975573..e60120d3f6a 100644 --- a/src/s/irix6-0.h +++ b/src/s/irix6-0.h @@ -35,3 +35,6 @@ /* Tested on Irix 6.5. SCM worked on earlier versions. */ #define GC_SETJMP_WORKS 1 #define GC_MARK_STACK GC_MAKE_GCPROS_NOOPS + +/* arch-tag: a775e465-a619-4655-a58f-5982aad0c624 + (do not change this comment) */ diff --git a/src/s/irix6-5.h b/src/s/irix6-5.h index 7e29dc284b1..c1cc42a8c0e 100644 --- a/src/s/irix6-5.h +++ b/src/s/irix6-5.h @@ -32,3 +32,6 @@ #undef ospeed #undef TIOCSIGSEND /* defined in usg5-4.h */ + +/* arch-tag: d7ad9ec2-54ad-4b2f-adf2-0070c5c63e83 + (do not change this comment) */ diff --git a/src/s/isc2-2.h b/src/s/isc2-2.h index f669fc2c141..88f216b77d8 100644 --- a/src/s/isc2-2.h +++ b/src/s/isc2-2.h @@ -75,3 +75,6 @@ /* Some versions of ISC are said to define S_IFLNK even tho they don't really support symlinks. */ #undef S_IFLNK + +/* arch-tag: 4de02713-eac5-4360-9d36-fd82c7a3ae44 + (do not change this comment) */ diff --git a/src/s/isc3-0.h b/src/s/isc3-0.h index 327f605ff7e..bbd4e8609d1 100644 --- a/src/s/isc3-0.h +++ b/src/s/isc3-0.h @@ -44,3 +44,6 @@ It won't be needed for 4.1. */ #define EXTRA_INITIALIZE __setostype (0) #endif + +/* arch-tag: c1aca3f2-813d-4c1c-ad64-ca6c20ec9bfb + (do not change this comment) */ diff --git a/src/s/isc4-0.h b/src/s/isc4-0.h index ccd6cb0627f..d180b5d182c 100644 --- a/src/s/isc4-0.h +++ b/src/s/isc4-0.h @@ -28,3 +28,6 @@ sigprocmask (SIG_SETMASK, &sigprocmask_set, NULL)) #endif #endif /* not POSIX_SIGNALS */ + +/* arch-tag: 1278f86f-17f2-462d-88c9-85e4b5faa5c3 + (do not change this comment) */ diff --git a/src/s/isc4-1.h b/src/s/isc4-1.h index df549b9fb7b..c37537e629c 100644 --- a/src/s/isc4-1.h +++ b/src/s/isc4-1.h @@ -30,3 +30,6 @@ /* ISC 4.1 has sys/wait.h but it does not work right. */ #undef HAVE_SYS_WAIT_H + +/* arch-tag: ec5c77d9-a330-4d93-8117-d2b374531c67 + (do not change this comment) */ diff --git a/src/s/lynxos.h b/src/s/lynxos.h index 576c4093c51..017e1892c10 100644 --- a/src/s/lynxos.h +++ b/src/s/lynxos.h @@ -54,3 +54,6 @@ Boston, MA 02111-1307, USA. */ /* warning messages */ #define C_SWITCH_SYSTEM -D__NO_INCLUDE_WARN__ #define LIBS_SYSTEM -lbsd + +/* arch-tag: fbc81ec9-1c45-416b-a368-799ae7c094a1 + (do not change this comment) */ diff --git a/src/s/mach-bsd4-3.h b/src/s/mach-bsd4-3.h index df4640b3fc5..e012679c5ff 100644 --- a/src/s/mach-bsd4-3.h +++ b/src/s/mach-bsd4-3.h @@ -3,3 +3,6 @@ you're in deep shit. */ #include "bsd4-3.h" + +/* arch-tag: 7f7f00f6-ae34-413e-9e6a-1d3b3e3d07e8 + (do not change this comment) */ diff --git a/src/s/ms-w32.h b/src/s/ms-w32.h index 6d38d4fa592..09d31ed2e04 100644 --- a/src/s/ms-w32.h +++ b/src/s/ms-w32.h @@ -492,3 +492,6 @@ extern void _DebPrint (const char *fmt, ...); /* ============================================================ */ + +/* arch-tag: 5d4a3a1c-40dc-4dea-9c7c-38fed9ae0eae + (do not change this comment) */ diff --git a/src/s/msdos.h b/src/s/msdos.h index 9c9205a33ad..cef2184a37b 100644 --- a/src/s/msdos.h +++ b/src/s/msdos.h @@ -275,3 +275,6 @@ You lose; /* Emacs for DOS must be compiled with DJGPP */ #define GC_SETJMP_WORKS 1 #define GC_MARK_STACK GC_MAKE_GCPROS_NOOPS + +/* arch-tag: d184f860-815d-4ff4-8187-d05c0f3c37d0 + (do not change this comment) */ diff --git a/src/s/netbsd.h b/src/s/netbsd.h index c48ac6d32fa..206ff55c854 100644 --- a/src/s/netbsd.h +++ b/src/s/netbsd.h @@ -138,3 +138,5 @@ #define GC_MARK_STACK GC_MAKE_GCPROS_NOOPS +/* arch-tag: e80f364a-04e9-4faf-93cb-f36a0fe95c81 + (do not change this comment) */ diff --git a/src/s/newsos5.h b/src/s/newsos5.h index 7c782a40cd4..f4ab0597eee 100644 --- a/src/s/newsos5.h +++ b/src/s/newsos5.h @@ -47,3 +47,6 @@ Boston, MA 02111-1307, USA. */ #ifndef HAVE_SOCKETS #define HAVE_SOCKETS #endif + +/* arch-tag: 2bb78fcd-fbc4-46dd-a14b-e4a9be957fe0 + (do not change this comment) */ diff --git a/src/s/newsos6.h b/src/s/newsos6.h index d4e67f7e4cf..ca3dbe706d0 100644 --- a/src/s/newsos6.h +++ b/src/s/newsos6.h @@ -4,3 +4,6 @@ #define NEWSOS6 #define HAVE_TEXT_START + +/* arch-tag: a0db9cb0-43bb-4f9e-85fa-384e30f02d74 + (do not change this comment) */ diff --git a/src/s/nextstep.h b/src/s/nextstep.h index e40cdb56ec7..36549e88bfa 100644 --- a/src/s/nextstep.h +++ b/src/s/nextstep.h @@ -110,3 +110,6 @@ Boston, MA 02111-1307, USA. */ /* Tell emacs.c not to define abort. */ #define NO_ABORT + +/* arch-tag: 5cd6fed4-a0be-4402-9349-85a80bc01d57 + (do not change this comment) */ diff --git a/src/s/openbsd.h b/src/s/openbsd.h index 7273f48e20f..d3730324ce8 100644 --- a/src/s/openbsd.h +++ b/src/s/openbsd.h @@ -23,3 +23,6 @@ #define LD_SWITCH_SYSTEM LD_SWITCH_SYSTEM_tmp #endif + +/* arch-tag: 7e3f65ca-3f48-4237-933f-2b208b21e8e2 + (do not change this comment) */ diff --git a/src/s/osf1.h b/src/s/osf1.h index e05f429a743..61ac04c5f1f 100644 --- a/src/s/osf1.h +++ b/src/s/osf1.h @@ -72,3 +72,6 @@ emacs_close (dummy); \ } \ while (0) + +/* arch-tag: 65eaea67-fcc3-4de7-8574-d46beb82d4ed + (do not change this comment) */ diff --git a/src/s/osf5-0.h b/src/s/osf5-0.h index eef028a6e3e..4f22f6d641b 100644 --- a/src/s/osf5-0.h +++ b/src/s/osf5-0.h @@ -20,3 +20,6 @@ #define GC_SETJMP_WORKS 1 #define GC_MARK_STACK GC_MAKE_GCPROS_NOOPS + +/* arch-tag: 89580064-dd8c-4533-a47c-0f92d8090945 + (do not change this comment) */ diff --git a/src/s/ptx.h b/src/s/ptx.h index ae76c35f3e6..dab0f0f205f 100644 --- a/src/s/ptx.h +++ b/src/s/ptx.h @@ -169,3 +169,6 @@ struct timezone /* Kenneth Stailey <kstailey@eagle.dol-esa.gov> says this is needed. */ #define POSIX_SIGNALS + +/* arch-tag: 4f5e3abc-643b-413a-bae6-ed212d3af997 + (do not change this comment) */ diff --git a/src/s/ptx4-2.h b/src/s/ptx4-2.h index cc8e2111cf7..3940093c28d 100644 --- a/src/s/ptx4-2.h +++ b/src/s/ptx4-2.h @@ -15,3 +15,6 @@ #ifdef _MALLOC_INTERNAL #define _POSIX_SOURCE #endif + +/* arch-tag: 10a9fab3-9e84-4e9e-9535-6ff42baf9e77 + (do not change this comment) */ diff --git a/src/s/ptx4.h b/src/s/ptx4.h index 2505a5dfa03..295cb27d1a3 100644 --- a/src/s/ptx4.h +++ b/src/s/ptx4.h @@ -35,3 +35,6 @@ fatal ("ioctl I_PUSH ldterm", errno); \ if (ioctl (xforkin, I_PUSH, "ttcompat") == -1 && errno != EINVAL) \ fatal ("ioctl I_PUSH ttcompat", errno); + +/* arch-tag: 14621824-8dca-432b-a97a-049fc4ce0e9f + (do not change this comment) */ diff --git a/src/s/riscix1-1.h b/src/s/riscix1-1.h index 605ed688bcd..15092f59add 100644 --- a/src/s/riscix1-1.h +++ b/src/s/riscix1-1.h @@ -23,3 +23,6 @@ Boston, MA 02111-1307, USA. */ #define RISCiX 11 #define CRT0_O /lib/crt0.o #include "bsd4-3.h" + +/* arch-tag: 382df034-9843-4a82-8a3a-2e50a4dd532c + (do not change this comment) */ diff --git a/src/s/riscix12.h b/src/s/riscix12.h index cbc78d58b95..988fbd61ba0 100644 --- a/src/s/riscix12.h +++ b/src/s/riscix12.h @@ -23,3 +23,6 @@ Boston, MA 02111-1307, USA. */ #define RISCiX 12 #define CRT0_O /usr/lib/crt0.o #include "bsd4-3.h" + +/* arch-tag: f6b21e0a-f676-418a-9c8a-10fa8cd9dba7 + (do not change this comment) */ diff --git a/src/s/riscos5.h b/src/s/riscos5.h index c4b1919bf06..6ebf412c1d6 100644 --- a/src/s/riscos5.h +++ b/src/s/riscos5.h @@ -9,3 +9,6 @@ extern double atof (); #define LD_SWITCH_SYSTEM -non_shared #define GETPGRP_NO_ARG + +/* arch-tag: e8ddf21d-72a0-476d-b33e-364f8b20e3b7 + (do not change this comment) */ diff --git a/src/s/rtu.h b/src/s/rtu.h index 80dccaafc8d..afe63b5efcc 100644 --- a/src/s/rtu.h +++ b/src/s/rtu.h @@ -144,3 +144,6 @@ Boston, MA 02111-1307, USA. */ /* Process groups work in the traditional BSD manner. */ #define BSD_PGRPS + +/* arch-tag: 0908970b-1cc0-4d57-b866-61b9bd029a0d + (do not change this comment) */ diff --git a/src/s/sco4.h b/src/s/sco4.h index 67b96eee59a..b39c7a75459 100644 --- a/src/s/sco4.h +++ b/src/s/sco4.h @@ -141,3 +141,6 @@ Boston, MA 02111-1307, USA. */ #define NO_SOCKETS_IN_FILE_SYSTEM #define NARROWPROTO 1 + +/* arch-tag: 4dd6fe94-bcb7-4be0-942a-ff4bc3cd914e + (do not change this comment) */ diff --git a/src/s/sco5.h b/src/s/sco5.h index 8b091f63b53..096944b833d 100644 --- a/src/s/sco5.h +++ b/src/s/sco5.h @@ -171,3 +171,6 @@ extern SIGMASKTYPE sigprocmask_set; #define LIB_STANDARD -lc /usr/ccs/lib/crtn.o #define NARROWPROTO 1 + +/* arch-tag: 930541b5-52d9-4cbe-b73c-f4c72091f5df + (do not change this comment) */ diff --git a/src/s/sol2-3.h b/src/s/sol2-3.h index a4fc6097905..b45ec57ef1f 100644 --- a/src/s/sol2-3.h +++ b/src/s/sol2-3.h @@ -48,3 +48,6 @@ strncpy (pty_name, ptyname, sizeof (pty_name)); \ pty_name[sizeof (pty_name) - 1] = 0; \ } + +/* arch-tag: a8fe2e15-e517-49cb-a863-f346b80885fe + (do not change this comment) */ diff --git a/src/s/sol2-4.h b/src/s/sol2-4.h index ad4fb0c5fd6..8ac97eaa6df 100644 --- a/src/s/sol2-4.h +++ b/src/s/sol2-4.h @@ -33,3 +33,5 @@ are in this directory on Solaris 2.4. */ #define C_SWITCH_X_SYSTEM -I/usr/dt/include +/* arch-tag: 6f0de37b-cfda-427a-a5ae-b83ed54aaae7 + (do not change this comment) */ diff --git a/src/s/sol2-5.h b/src/s/sol2-5.h index 600ab999486..e02f0b82bc0 100644 --- a/src/s/sol2-5.h +++ b/src/s/sol2-5.h @@ -31,3 +31,6 @@ /* Probably OK also on earlier versions. */ #define GC_SETJMP_WORKS 1 #define GC_MARK_STACK GC_MAKE_GCPROS_NOOPS + +/* arch-tag: 96d65526-21c9-4547-a797-2bd575c05be7 + (do not change this comment) */ diff --git a/src/s/sol2-6.h b/src/s/sol2-6.h index 94651397658..a43443e48c2 100644 --- a/src/s/sol2-6.h +++ b/src/s/sol2-6.h @@ -6,3 +6,6 @@ #undef UNEXEC #define UNEXEC unexsol.o #endif + +/* arch-tag: 71ea3857-89dc-4395-9623-77964e6ed3ca + (do not change this comment) */ diff --git a/src/s/sol2.h b/src/s/sol2.h index ed82812bc67..5f7d781f3e3 100644 --- a/src/s/sol2.h +++ b/src/s/sol2.h @@ -51,3 +51,6 @@ #endif #define USE_MMAP_FOR_BUFFERS 1 + +/* arch-tag: b0640f78-5ad5-4093-97c3-5b3abbf5a2be + (do not change this comment) */ diff --git a/src/s/sunos4-0.h b/src/s/sunos4-0.h index 0b192f8ae00..d108df68640 100644 --- a/src/s/sunos4-0.h +++ b/src/s/sunos4-0.h @@ -47,3 +47,6 @@ #define GC_SETJMP_WORKS 1 #define GC_MARK_STACK GC_MAKE_GCPROS_NOOPS + +/* arch-tag: 362f3bfc-810d-4f6e-9b83-5a32f8f1a926 + (do not change this comment) */ diff --git a/src/s/sunos4-1.h b/src/s/sunos4-1.h index 9c6b9cede23..2e41c55bbfe 100644 --- a/src/s/sunos4-1.h +++ b/src/s/sunos4-1.h @@ -31,3 +31,6 @@ /* Define dlopen, dlclose, dlsym. */ #define USE_DL_STUBS + +/* arch-tag: 154e2eb2-2180-4d66-90b9-7e56a22004f2 + (do not change this comment) */ diff --git a/src/s/sunos413.h b/src/s/sunos413.h index 5dedb2947f6..9f40f2fa3af 100644 --- a/src/s/sunos413.h +++ b/src/s/sunos413.h @@ -11,3 +11,6 @@ #endif #define USE_MMAP_FOR_BUFFERS 1 + +/* arch-tag: ebd184b0-9084-4306-8e71-c0437330e1e1 + (do not change this comment) */ diff --git a/src/s/sunos4shr.h b/src/s/sunos4shr.h index d6335326bbb..8427201cda3 100644 --- a/src/s/sunos4shr.h +++ b/src/s/sunos4shr.h @@ -57,3 +57,6 @@ #endif #endif /* not HAVE_X11R6 */ + +/* arch-tag: cb54321a-ed45-4c17-a23e-1c157758da78 + (do not change this comment) */ diff --git a/src/s/template.h b/src/s/template.h index f4d806de146..e969c72e0aa 100644 --- a/src/s/template.h +++ b/src/s/template.h @@ -184,3 +184,6 @@ Boston, MA 02111-1307, USA. */ If you've just fixed a problem in an existing configuration file, you should also check `etc/MACHINES' to make sure its descriptions of known problems in that configuration should be updated. */ + +/* arch-tag: 4b426b11-cb2e-4c0e-a488-e663f76a0515 + (do not change this comment) */ diff --git a/src/s/ultrix4-3.h b/src/s/ultrix4-3.h index c8d5e4a324e..2b4f379d3d1 100644 --- a/src/s/ultrix4-3.h +++ b/src/s/ultrix4-3.h @@ -11,3 +11,6 @@ /* The address of this is used, but Ultrix header files don't declare it. */ extern double rint (); #endif + +/* arch-tag: 927a396a-d50f-494b-960b-533671184ce1 + (do not change this comment) */ diff --git a/src/s/umax.h b/src/s/umax.h index eaa9b6c4bbc..36f5499a4b3 100644 --- a/src/s/umax.h +++ b/src/s/umax.h @@ -164,3 +164,6 @@ Boston, MA 02111-1307, USA. */ /* Process groups work in the traditional BSD manner. */ #define BSD_PGRPS + +/* arch-tag: 2860edda-ce9e-4cfa-943d-3a06c7045854 + (do not change this comment) */ diff --git a/src/s/umips.h b/src/s/umips.h index 1b573842ea4..3d497892c4b 100644 --- a/src/s/umips.h +++ b/src/s/umips.h @@ -69,3 +69,6 @@ /* High order bit must be stripped off nlist return values */ #define FIXUP_KERNEL_SYMBOL_ADDR(NL) (NL)[0].n_value &= 0x7fffffff; + +/* arch-tag: 9b816c7d-6ee2-40d9-b6dc-42c0aeccfbec + (do not change this comment) */ diff --git a/src/s/unipl5-2.h b/src/s/unipl5-2.h index 9e61d3fac7c..0a395b22a09 100644 --- a/src/s/unipl5-2.h +++ b/src/s/unipl5-2.h @@ -154,3 +154,6 @@ Boston, MA 02111-1307, USA. */ /* A system-specific loader switch is needed. */ #define LD_SWITCH_SYSTEM -N -L/lib/libg /usr/lib/unshared.ld + +/* arch-tag: d3f952a9-fef5-45d5-9c1e-c1c32bfef86c + (do not change this comment) */ diff --git a/src/s/unixware.h b/src/s/unixware.h index a4b02531bce..934821dd166 100644 --- a/src/s/unixware.h +++ b/src/s/unixware.h @@ -1,3 +1,6 @@ #include "usg5-4-2.h" #define PENDING_OUTPUT_COUNT(FILE) ((FILE)->__ptr - (FILE)->__base) + +/* arch-tag: d82e92e7-9443-4a60-a581-7f293cbae8a3 + (do not change this comment) */ diff --git a/src/s/usg5-0.h b/src/s/usg5-0.h index 885ad00b1ba..ecce9d92c76 100644 --- a/src/s/usg5-0.h +++ b/src/s/usg5-0.h @@ -151,3 +151,6 @@ Boston, MA 02111-1307, USA. */ /* Prevent -lg from being used for debugging. Not implemented? */ #define LIBS_DEBUG + +/* arch-tag: a18bdba9-506d-40ed-9877-49fc27ce8cac + (do not change this comment) */ diff --git a/src/s/usg5-2-2.h b/src/s/usg5-2-2.h index 0c8e3c3d2df..a360fd64d7a 100644 --- a/src/s/usg5-2-2.h +++ b/src/s/usg5-2-2.h @@ -154,3 +154,6 @@ Boston, MA 02111-1307, USA. */ /* Use terminfo instead of termcap. */ #define TERMINFO + +/* arch-tag: 56923f22-9e2b-4814-b922-88c87657ff6b + (do not change this comment) */ diff --git a/src/s/usg5-2.h b/src/s/usg5-2.h index e6f586da28d..375dba75f56 100644 --- a/src/s/usg5-2.h +++ b/src/s/usg5-2.h @@ -154,3 +154,6 @@ Boston, MA 02111-1307, USA. */ /* Use terminfo instead of termcap. */ #define TERMINFO + +/* arch-tag: cfd9500f-0284-4a88-8f07-3f56b42db13b + (do not change this comment) */ diff --git a/src/s/usg5-3.h b/src/s/usg5-3.h index 5323bb694a6..de1a20d2658 100644 --- a/src/s/usg5-3.h +++ b/src/s/usg5-3.h @@ -205,3 +205,6 @@ Boston, MA 02111-1307, USA. */ /* On USG systems signal handlers return void */ #define SIGTYPE void + +/* arch-tag: 2bca65fd-f015-44b9-a2aa-9f8170ce89ca + (do not change this comment) */ diff --git a/src/s/usg5-4-2.h b/src/s/usg5-4-2.h index 351d51fe29b..8b11bc54eae 100644 --- a/src/s/usg5-4-2.h +++ b/src/s/usg5-4-2.h @@ -54,3 +54,6 @@ /* ryanr@ellingtn.ftc.nrcs.usda.gov (Richard Anthony Ryan) says -lXimp is needed in UNIX_SV ... 4.2 1.1.2. */ #define LIB_MOTIF -lXm -lXimp + +/* arch-tag: 9bbfcfc1-19be-45a1-9699-af57b87da2c6 + (do not change this comment) */ diff --git a/src/s/usg5-4-3.h b/src/s/usg5-4-3.h index f7773cb0a13..8d05e8b3fa6 100644 --- a/src/s/usg5-4-3.h +++ b/src/s/usg5-4-3.h @@ -6,3 +6,6 @@ on start up for an i486-ncr-sysv4.3 (running the X toolkit): _XipOpenIM() Unable to find Atom _XIM_INPUTMETHOD */ #define X11R5_INHIBIT_I18N + +/* arch-tag: 03ac8b3a-c3d4-4441-a773-1c1d9f111f1a + (do not change this comment) */ diff --git a/src/s/usg5-4.h b/src/s/usg5-4.h index 49554b9456f..719b8c389a3 100644 --- a/src/s/usg5-4.h +++ b/src/s/usg5-4.h @@ -193,3 +193,6 @@ Boston, MA 02111-1307, USA. */ SINIX. */ #undef LIBS_SYSTEM #define LIBS_SYSTEM -lgen + +/* arch-tag: 1a0ed909-5faa-434b-b7c3-9d86c63d53a6 + (do not change this comment) */ diff --git a/src/s/ux4800.h b/src/s/ux4800.h index 6544bfdebe3..1c8729f416b 100644 --- a/src/s/ux4800.h +++ b/src/s/ux4800.h @@ -15,3 +15,6 @@ #ifndef __GNUC__ #define C_DEBUG_SWITCH -O -KOlimit=3000 -ZXNd=5000 #endif + +/* arch-tag: e42eeb13-028a-490b-8427-0b57010f2ab9 + (do not change this comment) */ diff --git a/src/s/uxpds.h b/src/s/uxpds.h index 0b823aaab0d..c3ddf1039c1 100644 --- a/src/s/uxpds.h +++ b/src/s/uxpds.h @@ -6,3 +6,6 @@ #define XOS_NEEDS_TIME_H #define FSCALE 256 + +/* arch-tag: c02db2a6-c725-4a6b-adee-66e0303df2a8 + (do not change this comment) */ diff --git a/src/s/uxpv.h b/src/s/uxpv.h index 94ea91eb1a1..95715455984 100644 --- a/src/s/uxpv.h +++ b/src/s/uxpv.h @@ -9,3 +9,6 @@ #undef SYSTEM_TYPE #define SYSTEM_TYPE "uxpv" + +/* arch-tag: 3f00cfe7-f44c-45ce-a2fe-2b17fc411a1e + (do not change this comment) */ diff --git a/src/s/vms.h b/src/s/vms.h index 9f718099eef..dc7877eaa67 100644 --- a/src/s/vms.h +++ b/src/s/vms.h @@ -246,3 +246,6 @@ globalref char sdata[]; /* What separator do we use in paths? */ #define SEPCHAR ',' + +/* arch-tag: 76bc2b70-46d1-4334-8f12-955c0d0ca6d4 + (do not change this comment) */ diff --git a/src/s/vms4-0.h b/src/s/vms4-0.h index 3f11a3de30a..c7e0c7be585 100644 --- a/src/s/vms4-0.h +++ b/src/s/vms4-0.h @@ -1,2 +1,5 @@ #include "vms.h" #define VMS4_0 + +/* arch-tag: 734e1c69-d514-4441-bbcd-8b5db8ab1892 + (do not change this comment) */ diff --git a/src/s/vms4-2.h b/src/s/vms4-2.h index e632b87e09f..01ee788dd66 100644 --- a/src/s/vms4-2.h +++ b/src/s/vms4-2.h @@ -1,3 +1,5 @@ #include "vms.h" #define VMS4_2 +/* arch-tag: d9ff67bc-a899-44b2-a618-a73c821bb559 + (do not change this comment) */ diff --git a/src/s/vms4-4.h b/src/s/vms4-4.h index c0f60900d53..0abd8259143 100644 --- a/src/s/vms4-4.h +++ b/src/s/vms4-4.h @@ -1,3 +1,5 @@ #include "vms.h" #define VMS4_4 +/* arch-tag: 2e65c7ad-0d17-45a0-b4cb-3e76c72ea9d5 + (do not change this comment) */ diff --git a/src/s/vms5-5.h b/src/s/vms5-5.h index e51fedf6317..ac0ba9461a2 100644 --- a/src/s/vms5-5.h +++ b/src/s/vms5-5.h @@ -6,3 +6,6 @@ And defining it causes lossage because sys_errlist has a different number of elements. */ #undef SHARABLE_LIB_BUG + +/* arch-tag: 92acc416-61fe-44ae-b0e0-710cb9e38ec6 + (do not change this comment) */ diff --git a/src/s/windows95.h b/src/s/windows95.h index 62340c3744e..cf7f3f13c88 100644 --- a/src/s/windows95.h +++ b/src/s/windows95.h @@ -3,3 +3,6 @@ #include "windowsnt.h" #define WINDOWS95 + +/* arch-tag: 8a37be6f-312c-4b2a-919e-58a71a0fb4b3 + (do not change this comment) */ diff --git a/src/s/xenix.h b/src/s/xenix.h index be742120b60..c0840bcd3b3 100644 --- a/src/s/xenix.h +++ b/src/s/xenix.h @@ -206,3 +206,6 @@ Boston, MA 02111-1307, USA. */ are not declared. */ #define BROKEN_TIOCGETC + +/* arch-tag: 71d3985d-4e53-4572-8276-5dce26bbd076 + (do not change this comment) */ diff --git a/src/scroll.c b/src/scroll.c index d7535509007..6c6aa4abf98 100644 --- a/src/scroll.c +++ b/src/scroll.c @@ -1069,3 +1069,6 @@ do_line_insertion_deletion_costs (frame, FRAME_DELETE_COST (frame), FRAME_DELETEN_COST (frame), coefficient); } + +/* arch-tag: cdb7149c-48e7-4793-a948-2786c8e45485 + (do not change this comment) */ diff --git a/src/sound.c b/src/sound.c index c43cb49d3c4..134b69dc81c 100644 --- a/src/sound.c +++ b/src/sound.c @@ -1143,3 +1143,6 @@ init_sound () } #endif /* HAVE_SOUND */ + +/* arch-tag: dd850ad8-0433-4e2c-9cba-b7aeeccc0dbd + (do not change this comment) */ diff --git a/src/strftime.c b/src/strftime.c index 4ca6023aa41..4d3a9d1d312 100644 --- a/src/strftime.c +++ b/src/strftime.c @@ -1491,3 +1491,6 @@ emacs_strftimeu (s, maxsize, format, tp, ut) return my_strftime (s, maxsize, format, tp, ut, 0); } #endif + +/* arch-tag: 662bc9c4-f8e2-41b6-bf96-b8346d0ce0d8 + (do not change this comment) */ diff --git a/src/sunfns.c b/src/sunfns.c index 8f8bb102765..13fdfd3a1b7 100644 --- a/src/sunfns.c +++ b/src/sunfns.c @@ -299,7 +299,7 @@ sel_read (sel, file) error("fread botch in sel_read"); return(-1); } else if (n < 0) { - error("Error reading selection."); + error("Error reading selection"); return(-1); } /* @@ -513,3 +513,6 @@ syms_of_sunfns() defsubr(&Ssun_get_selection); defsubr(&Ssun_menu_internal); } + +/* arch-tag: 2d7decb7-58f6-41aa-b45b-077ccfab7158 + (do not change this comment) */ diff --git a/src/syntax.c b/src/syntax.c index 680a4bcaf87..22a34c40fb3 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -2584,8 +2584,8 @@ scan_lists (from, count, depth, sexpflag) case Sstring_fence: while (1) { - DEC_BOTH (from, from_byte); if (from == stop) goto lose; + DEC_BOTH (from, from_byte); UPDATE_SYNTAX_TABLE_BACKWARD (from); if (!char_quoted (from, from_byte) && (c = FETCH_CHAR_AS_MULTIBYTE (from_byte), @@ -2600,19 +2600,14 @@ scan_lists (from, count, depth, sexpflag) while (1) { if (from == stop) goto lose; - temp_pos = from_byte; - if (! NILP (current_buffer->enable_multibyte_characters)) - DEC_POS (temp_pos); - else - temp_pos--; - UPDATE_SYNTAX_TABLE_BACKWARD (from - 1); - if (!char_quoted (from - 1, temp_pos) - && stringterm == (c = FETCH_CHAR_AS_MULTIBYTE (temp_pos)) + DEC_BOTH (from, from_byte); + UPDATE_SYNTAX_TABLE_BACKWARD (from); + if (!char_quoted (from, from_byte) + && (stringterm + == (c = FETCH_CHAR_AS_MULTIBYTE (from_byte))) && SYNTAX_WITH_MULTIBYTE_CHECK (c) == Sstring) break; - DEC_BOTH (from, from_byte); } - DEC_BOTH (from, from_byte); if (!depth && sexpflag) goto done2; break; default: diff --git a/src/sysdep.c b/src/sysdep.c index 193f0630cbf..5ede3d27208 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -24,6 +24,7 @@ Boston, MA 02111-1307, USA. */ #endif #include <signal.h> +#include <stdio.h> #include <setjmp.h> #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -80,7 +81,6 @@ static int delete_exited_processes; #undef fwrite #endif -#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> @@ -2614,13 +2614,6 @@ sys_select (nfds, rfds, wfds, efds, timeout) /* Read keyboard input into the standard buffer, waiting for at least one character. */ -/* Make all keyboard buffers much bigger when using a window system. */ -#ifdef HAVE_WINDOW_SYSTEM -#define BUFFER_SIZE_FACTOR 16 -#else -#define BUFFER_SIZE_FACTOR 1 -#endif - void read_input_waiting () { @@ -2629,26 +2622,19 @@ read_input_waiting () if (read_socket_hook) { - struct input_event buf[256]; - for (i = 0; i < 256; i++) - EVENT_INIT (buf[i]); - + struct input_event hold_quit; + + EVENT_INIT (hold_quit); + hold_quit.kind = NO_EVENT; + read_alarm_should_throw = 0; if (! setjmp (read_alarm_throw)) - nread = (*read_socket_hook) (0, buf, 256, 1); + nread = (*read_socket_hook) (0, 1, &hold_quit); else nread = -1; - /* Scan the chars for C-g and store them in kbd_buffer. */ - for (i = 0; i < nread; i++) - { - kbd_buffer_store_event (&buf[i]); - /* Don't look at input that follows a C-g too closely. - This reduces lossage due to autorepeat on C-g. */ - if (buf[i].kind == ASCII_KEYSTROKE_EVENT - && buf[i].code == quit_char) - break; - } + if (hold_quit.kind != NO_EVENT) + kbd_buffer_store_event (&hold_quit); } else { @@ -3741,7 +3727,8 @@ mkdir (dpath, dmode) wait_for_termination (cpid); } - if (synch_process_death != 0 || synch_process_retcode != 0) + if (synch_process_death != 0 || synch_process_retcode != 0 + || synch_process_termsig != 0) { errno = EIO; /* We don't know why, but */ return -1; /* /bin/mkdir failed */ @@ -3787,7 +3774,8 @@ rmdir (dpath) wait_for_termination (cpid); } - if (synch_process_death != 0 || synch_process_retcode != 0) + if (synch_process_death != 0 || synch_process_retcode != 0 + || synch_process_termsig != 0) { errno = EIO; /* We don't know why, but */ return -1; /* /bin/rmdir failed */ @@ -5298,3 +5286,5 @@ strsignal (code) } #endif /* HAVE_STRSIGNAL */ +/* arch-tag: edb43589-4e09-4544-b325-978b5b121dcf + (do not change this comment) */ diff --git a/src/sysselect.h b/src/sysselect.h index 5a392c381a7..5aa9eb4aee7 100644 --- a/src/sysselect.h +++ b/src/sysselect.h @@ -43,3 +43,6 @@ Boston, MA 02111-1307, USA. */ #if !defined (HAVE_SELECT) || defined (BROKEN_SELECT_NON_X) #define select sys_select #endif + +/* arch-tag: 36d05500-8cf6-4847-8e78-6721f18c06ef + (do not change this comment) */ diff --git a/src/syssignal.h b/src/syssignal.h index 2a579f3ba45..2b536758e27 100644 --- a/src/syssignal.h +++ b/src/syssignal.h @@ -196,3 +196,6 @@ extern SIGMASKTYPE sigprocmask_set; /* strsignal is in sysdep.c */ char *strsignal (); #endif + +/* arch-tag: 4580e86a-340d-4574-9e11-a742b6e1a152 + (do not change this comment) */ diff --git a/src/systime.h b/src/systime.h index d05b5a7de9a..778e555c979 100644 --- a/src/systime.h +++ b/src/systime.h @@ -172,3 +172,6 @@ extern int set_file_times __P ((const char *, EMACS_TIME, EMACS_TIME)); #define EMACS_TIME_LE(T1, T2) (EMACS_TIME_CMP (T1, T2) <= 0) #endif /* EMACS_SYSTIME_H */ + +/* arch-tag: dcb79915-cf99-4bce-9778-aade71d07651 + (do not change this comment) */ diff --git a/src/systty.h b/src/systty.h index 39ae61be1c9..a975bcd13a0 100644 --- a/src/systty.h +++ b/src/systty.h @@ -387,3 +387,6 @@ extern int emacs_set_tty P_ ((int, struct emacs_tty *, int)); #endif /* not def VMS */ #endif /* not def HAVE_TERMIO */ #endif /* not def HAVE_TERMIOS */ + +/* arch-tag: cf4b90bc-be41-401c-be98-40619178a712 + (do not change this comment) */ diff --git a/src/syswait.h b/src/syswait.h index 9b0a6899f87..066f4e5a482 100644 --- a/src/syswait.h +++ b/src/syswait.h @@ -152,3 +152,6 @@ Boston, MA 02111-1307, USA. */ #endif /* VMS */ #endif /* EMACS_SYSWAIT_H */ + +/* arch-tag: 7e5d9719-ec66-4b6f-89bb-563eea16a899 + (do not change this comment) */ diff --git a/src/term.c b/src/term.c index d4432a26316..609efcb8439 100644 --- a/src/term.c +++ b/src/term.c @@ -81,6 +81,10 @@ static void tty_hide_cursor P_ ((void)); #define OUTPUT1_IF(a) do { if (a) tputs (a, 1, cmputc); } while (0) +/* Display space properties */ + +extern Lisp_Object Qspace, QCalign_to, QCwidth; + /* Function to use to ring the bell. */ Lisp_Object Vring_bell_function; @@ -133,7 +137,7 @@ void (*insert_glyphs_hook) P_ ((struct glyph *, int)); void (*write_glyphs_hook) P_ ((struct glyph *, int)); void (*delete_glyphs_hook) P_ ((int)); -int (*read_socket_hook) P_ ((int, struct input_event *, int, int)); +int (*read_socket_hook) P_ ((int, int, struct input_event *)); void (*frame_up_to_date_hook) P_ ((struct frame *)); @@ -1584,6 +1588,7 @@ term_get_fkeys_1 () ***********************************************************************/ static void append_glyph P_ ((struct it *)); +static void produce_stretch_glyph P_ ((struct it *)); /* Append glyphs to IT's glyph_row. Called from produce_glyphs for @@ -1647,9 +1652,14 @@ produce_glyphs (it) /* If a hook is installed, let it do the work. */ xassert (it->what == IT_CHARACTER || it->what == IT_COMPOSITION - || it->what == IT_IMAGE || it->what == IT_STRETCH); + if (it->what == IT_STRETCH) + { + produce_stretch_glyph (it); + goto done; + } + /* Nothing but characters are supported on terminal frames. For a composition sequence, it->c is the first character of the sequence. */ @@ -1716,6 +1726,7 @@ produce_glyphs (it) append_glyph (it); } + done: /* Advance current_x by the pixel width as a convenience for the caller. */ if (it->area == TEXT_AREA) @@ -1725,6 +1736,81 @@ produce_glyphs (it) } +/* Produce a stretch glyph for iterator IT. IT->object is the value + of the glyph property displayed. The value must be a list + `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs + being recognized: + + 1. `:width WIDTH' specifies that the space should be WIDTH * + canonical char width wide. WIDTH may be an integer or floating + point number. + + 2. `:align-to HPOS' specifies that the space should be wide enough + to reach HPOS, a value in canonical character units. */ + +static void +produce_stretch_glyph (it) + struct it *it; +{ + /* (space :width WIDTH ...) */ + Lisp_Object prop, plist; + int width = 0, align_to = -1; + int zero_width_ok_p = 0; + double tem; + + /* List should start with `space'. */ + xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace)); + plist = XCDR (it->object); + + /* Compute the width of the stretch. */ + if ((prop = Fplist_get (plist, QCwidth), !NILP (prop)) + && calc_pixel_width_or_height (&tem, it, prop, 0, 1, 0)) + { + /* Absolute width `:width WIDTH' specified and valid. */ + zero_width_ok_p = 1; + width = (int)(tem + 0.5); + } + else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop)) + && calc_pixel_width_or_height (&tem, it, prop, 0, 1, &align_to)) + { + if (it->glyph_row == NULL || !it->glyph_row->mode_line_p) + align_to = (align_to < 0 + ? 0 + : align_to - window_box_left_offset (it->w, TEXT_AREA)); + else if (align_to < 0) + align_to = window_box_left_offset (it->w, TEXT_AREA); + width = max (0, (int)(tem + 0.5) + align_to - it->current_x); + zero_width_ok_p = 1; + } + else + /* Nothing specified -> width defaults to canonical char width. */ + width = FRAME_COLUMN_WIDTH (it->f); + + if (width <= 0 && (width < 0 || !zero_width_ok_p)) + width = 1; + + if (width > 0 && it->glyph_row) + { + Lisp_Object o_object = it->object; + Lisp_Object object = it->stack[it->sp - 1].string; + int n = width; + int c = it->c; + + if (!STRINGP (object)) + object = it->w->buffer; + it->object = object; + it->c = ' '; + it->pixel_width = it->len = 1; + while (n--) + append_glyph (it); + it->object = o_object; + it->c = c; + } + it->pixel_width = width; + it->nglyphs = width; +} + + /* Get information about special display element WHAT in an environment described by IT. WHAT is one of IT_TRUNCATION or IT_CONTINUATION. Maybe produce glyphs for WHAT if IT has a @@ -2048,6 +2134,10 @@ void tty_setup_colors (mode) int mode; { + /* Canonicalize all negative values of MODE. */ + if (mode < -1) + mode = -1; + switch (mode) { case -1: /* no colors at all */ @@ -2090,7 +2180,7 @@ set_tty_color_mode (f, val) tty_color_mode_alist = Fintern_soft (build_string ("tty-color-mode-alist"), Qnil); - if (NATNUMP (val)) + if (INTEGERP (val)) color_mode = val; else { @@ -2098,22 +2188,24 @@ set_tty_color_mode (f, val) color_mode_spec = Qnil; else color_mode_spec = Fassq (val, XSYMBOL (tty_color_mode_alist)->value); - current_mode_spec = assq_no_quit (Qtty_color_mode, f->param_alist); if (CONSP (color_mode_spec)) color_mode = XCDR (color_mode_spec); else color_mode = Qnil; } + + current_mode_spec = assq_no_quit (Qtty_color_mode, f->param_alist); + if (CONSP (current_mode_spec)) current_mode = XCDR (current_mode_spec); else current_mode = Qnil; - if (NATNUMP (color_mode)) + if (INTEGERP (color_mode)) mode = XINT (color_mode); else mode = 0; /* meaning default */ - if (NATNUMP (current_mode)) + if (INTEGERP (current_mode)) old_mode = XINT (current_mode); else old_mode = 0; @@ -2141,7 +2233,8 @@ term_init (terminal_type) { char *area; char **address = &area; - char buffer[2044]; + char *buffer = NULL; + int buffer_size = 4096; register char *p; int status; struct frame *sf = XFRAME (selected_frame); @@ -2153,9 +2246,6 @@ term_init (terminal_type) area = (char *) xmalloc (2044); - if (area == 0) - abort (); - FrameRows = FRAME_LINES (sf); FrameCols = FRAME_COLS (sf); specified_window = FRAME_LINES (sf); @@ -2184,6 +2274,7 @@ term_init (terminal_type) Wcm_clear (); + buffer = (char *) xmalloc (buffer_size); status = tgetent (buffer, terminal_type); if (status < 0) { @@ -2211,13 +2302,13 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.", terminal_type); #endif } -#ifdef TERMINFO - area = (char *) xmalloc (2044); -#else - area = (char *) xmalloc (strlen (buffer)); -#endif /* not TERMINFO */ - if (area == 0) + +#ifndef TERMINFO + if (strlen (buffer) >= buffer_size) abort (); + buffer_size = strlen (buffer); +#endif + area = (char *) xmalloc (buffer_size); TS_ins_line = tgetstr ("al", address); TS_ins_multi_lines = tgetstr ("AL", address); @@ -2550,6 +2641,8 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.", terminal_encode_buf_size = 1024; } #endif /* WINDOWSNT */ + + xfree (buffer); } /* VARARGS 1 */ @@ -2585,3 +2678,5 @@ The function should accept no arguments. */); defsubr (&Stty_display_color_cells); } +/* arch-tag: 498e7449-6f2e-45e2-91dd-b7d4ca488193 + (do not change this comment) */ diff --git a/src/termcap.c b/src/termcap.c index fa8d0ced0aa..a1c068e0964 100644 --- a/src/termcap.c +++ b/src/termcap.c @@ -284,6 +284,52 @@ tgetst1 (ptr, area) } *r++ = c; } + + /* Sometimes entries have "%pN" which means use parameter N in the + next %-substitution. If all such N are continuous in the range + [1,9] we can remove each "%pN" because they are redundant, thus + reducing bandwidth requirements. True, Emacs is well beyond the + days of 150baud teletypes, but some of its users aren't much so. + + This pass could probably be integrated into the one above but + abbreviation expansion makes that effort a little more hairy than + its worth; this is cleaner. */ + { + register int last_p_param = 0; + int remove_p_params = 1; + struct { char *beg; int len; } cut[11]; + + for (cut[0].beg = p = ret; p < r - 3; p++) + { + if (!remove_p_params) + break; + if (*p == '%' && *(p + 1) == 'p') + { + if (*(p + 2) - '0' == 1 + last_p_param) + { + cut[last_p_param].len = p - cut[last_p_param].beg; + last_p_param++; + p += 3; + cut[last_p_param].beg = p; + } + else /* not continuous: bail */ + remove_p_params = 0; + if (last_p_param > 10) /* too many: bail */ + remove_p_params = 0; + } + } + if (remove_p_params && last_p_param) + { + register int i; + char *wp; + + cut[last_p_param].len = r - cut[last_p_param].beg; + for (i = 0, wp = ret; i <= last_p_param; wp += cut[i++].len) + bcopy (cut[i].beg, wp, cut[i].len); + r = wp; + } + } + *r = '\0'; /* Update *AREA. */ if (area) @@ -828,3 +874,6 @@ tprint (cap) } #endif /* TEST */ + +/* arch-tag: c2e8d427-2271-4fac-95fe-411857238b80 + (do not change this comment) */ diff --git a/src/termchar.h b/src/termchar.h index da5413b8f9b..b1d941adc27 100644 --- a/src/termchar.h +++ b/src/termchar.h @@ -44,3 +44,6 @@ extern int dont_calculate_costs; /* Nonzero means don't bother computing a suspended Emacs. This is useful on terminals with multiple pages, where one page is used for Emacs and another for all else. */ extern int no_redraw_on_reenter; + +/* arch-tag: bf9f0d49-842b-42fb-9348-ec8759b27193 + (do not change this comment) */ diff --git a/src/termhooks.h b/src/termhooks.h index da41266d984..83721f65912 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -374,7 +374,7 @@ struct input_event #define EVENT_INIT(event) bzero (&(event), sizeof (struct input_event)) /* Called to read input events. */ -extern int (*read_socket_hook) P_ ((int, struct input_event *, int, int)); +extern int (*read_socket_hook) P_ ((int, int, struct input_event *)); /* Called when a frame's display becomes entirely up to date. */ extern void (*frame_up_to_date_hook) P_ ((struct frame *)); @@ -430,3 +430,6 @@ enum { }; #endif + +/* arch-tag: 33a00ecc-52b5-4186-a410-8801ac9f087d + (do not change this comment) */ diff --git a/src/terminfo.c b/src/terminfo.c index 8b41de4e47e..52acc5bdb4e 100644 --- a/src/terminfo.c +++ b/src/terminfo.c @@ -49,3 +49,6 @@ tparam (string, outstring, len, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, strcpy (outstring, temp); return outstring; } + +/* arch-tag: a6f96a69-e68f-4e9d-a223-f0b0da26ead5 + (do not change this comment) */ diff --git a/src/termopts.h b/src/termopts.h index 0fd240bd005..2dc798ea2c4 100644 --- a/src/termopts.h +++ b/src/termopts.h @@ -39,3 +39,6 @@ extern int meta_key; /* Nonzero means truncate lines in all windows less wide than the frame */ extern int truncate_partial_width_windows; + +/* arch-tag: 35d4d284-dc1a-4fff-97fa-0154a21aebdb + (do not change this comment) */ diff --git a/src/textprop.c b/src/textprop.c index d75e1cf2020..4f13aefb1be 100644 --- a/src/textprop.c +++ b/src/textprop.c @@ -703,6 +703,30 @@ overlays are considered only if they are associated with OBJECT. */) { return get_char_property_and_overlay (position, prop, object, 0); } + +DEFUN ("get-char-property-and-overlay", Fget_char_property_and_overlay, + Sget_char_property_and_overlay, 2, 3, 0, + doc: /* Like `get-char-property', but with extra overlay information. +Return a cons whose car is the return value of `get-char-property' +with the same arguments, that is, the value of POSITION's property +PROP in OBJECT, and whose cdr is the overlay in which the property was +found, or nil, if it was found as a text property or not found at all. +OBJECT is optional and defaults to the current buffer. OBJECT may be +a string, a buffer or a window. For strings, the cdr of the return +value is always nil, since strings do not have overlays. If OBJECT is +a window, then that window's buffer is used, but window-specific +overlays are considered only if they are associated with OBJECT. If +POSITION is at the end of OBJECT, both car and cdr are nil. */) + (position, prop, object) + Lisp_Object position, object; + register Lisp_Object prop; +{ + Lisp_Object overlay; + Lisp_Object val + = get_char_property_and_overlay (position, prop, object, &overlay); + return Fcons(val, overlay); +} + DEFUN ("next-char-property-change", Fnext_char_property_change, Snext_char_property_change, 1, 2, 0, @@ -2277,6 +2301,7 @@ rear-nonsticky properties of the character overrides NONSTICKINESS. */); defsubr (&Stext_properties_at); defsubr (&Sget_text_property); defsubr (&Sget_char_property); + defsubr (&Sget_char_property_and_overlay); defsubr (&Snext_char_property_change); defsubr (&Sprevious_char_property_change); defsubr (&Snext_single_char_property_change); @@ -2295,3 +2320,6 @@ rear-nonsticky properties of the character overrides NONSTICKINESS. */); /* defsubr (&Serase_text_properties); */ /* defsubr (&Scopy_text_properties); */ } + +/* arch-tag: 454cdde8-5f86-4faa-a078-101e3625d479 + (do not change this comment) */ diff --git a/src/tparam.c b/src/tparam.c index fb71e05b3e4..ea208692161 100644 --- a/src/tparam.c +++ b/src/tparam.c @@ -144,7 +144,9 @@ tparam1 (string, outstring, len, up, left, argp) int outlen = 0; register int tem; - int *old_argp = argp; + int *old_argp = argp; /* can move */ + int *fixed_argp = argp; /* never moves */ + int explicit_param_p = 0; /* set by %p */ int doleft = 0; int doup = 0; @@ -180,7 +182,10 @@ tparam1 (string, outstring, len, up, left, argp) if (c == '%') { c = *p++; - tem = *argp; + if (explicit_param_p) + explicit_param_p = 0; + else + tem = *argp; switch (c) { case 'd': /* %d means output in decimal. */ @@ -203,7 +208,10 @@ tparam1 (string, outstring, len, up, left, argp) *op++ = tem % 10 + '0'; argp++; break; - + case 'p': /* %pN means use param N for next subst. */ + tem = fixed_argp[(*p++) - '1']; + explicit_param_p = 1; + break; case 'C': /* For c-100: print quotient of value by 96, if nonzero, then do like %+. */ @@ -334,3 +342,6 @@ main (argc, argv) } #endif /* DEBUG */ + +/* arch-tag: 83f7b5ac-a808-4f75-b87a-123de009b402 + (do not change this comment) */ diff --git a/src/uaf.h b/src/uaf.h index 57615ab4527..ae364b5f5ef 100644 --- a/src/uaf.h +++ b/src/uaf.h @@ -294,3 +294,6 @@ struct UAF { }; #endif /* not UAF$K_LENGTH */ + +/* arch-tag: f95d73be-b0bf-46b7-adf7-89ce8846b062 + (do not change this comment) */ diff --git a/src/undo.c b/src/undo.c index fa802fe205a..dd086db6c40 100644 --- a/src/undo.c +++ b/src/undo.c @@ -554,3 +554,6 @@ syms_of_undo () defsubr (&Sprimitive_undo); defsubr (&Sundo_boundary); } + +/* arch-tag: d546ee01-4aed-4ffb-bb8b-eefaae50d38a + (do not change this comment) */ diff --git a/src/unexaix.c b/src/unexaix.c index 3c629346bc0..825209a5b3c 100644 --- a/src/unexaix.c +++ b/src/unexaix.c @@ -676,3 +676,6 @@ unrelocate_symbols (int new, int a_out, char *a_name, char *new_name) } return 0; } + +/* arch-tag: 0783857a-7c2d-456f-a426-58b722d69fd0 + (do not change this comment) */ diff --git a/src/unexalpha.c b/src/unexalpha.c index a76654a1277..97f8f383dda 100644 --- a/src/unexalpha.c +++ b/src/unexalpha.c @@ -540,3 +540,6 @@ fatal_unexec (s, arg) fputs (".\n", stderr); exit (1); } + +/* arch-tag: 46316c49-ee08-4aa3-942b-00798902f5bd + (do not change this comment) */ diff --git a/src/unexapollo.c b/src/unexapollo.c index 4a5ab60b254..adf72bb4f7a 100644 --- a/src/unexapollo.c +++ b/src/unexapollo.c @@ -295,3 +295,6 @@ CopyData (target_file, source_file, total_byte_count) total_byte_count -= byte_count; } } + +/* arch-tag: 783ebbdf-7d26-4df8-9469-17a1747dce96 + (do not change this comment) */ diff --git a/src/unexconvex.c b/src/unexconvex.c index a040add1224..10c0dfa953c 100644 --- a/src/unexconvex.c +++ b/src/unexconvex.c @@ -600,3 +600,5 @@ first_pty_letter () return 'a'; } +/* arch-tag: 8199e06d-69b5-4f79-84d8-00f6ea929af9 + (do not change this comment) */ diff --git a/src/unexec.c b/src/unexec.c index aa4170019c7..dadea560e0c 100644 --- a/src/unexec.c +++ b/src/unexec.c @@ -1265,3 +1265,6 @@ adjust_lnnoptrs (writedesc, readdesc, new_name) #endif /* COFF */ #endif /* not CANNOT_DUMP */ + +/* arch-tag: 62409b69-e27a-4a7c-9413-0210d6b54e7f + (do not change this comment) */ diff --git a/src/unexelf.c b/src/unexelf.c index d88b8ec37c0..ce773190d7e 100644 --- a/src/unexelf.c +++ b/src/unexelf.c @@ -1284,3 +1284,6 @@ unexec (new_name, old_name, data_start, bss_start, entry_address) if (chmod (new_name, stat_buf.st_mode) == -1) fatal ("Can't chmod (%s): errno %d\n", new_name, errno); } + +/* arch-tag: e02e1512-95e2-4ef0-bba7-b6bce658f1e3 + (do not change this comment) */ diff --git a/src/unexenix.c b/src/unexenix.c index 2121c26839f..a6d045d2e4f 100644 --- a/src/unexenix.c +++ b/src/unexenix.c @@ -258,3 +258,6 @@ fatal_unexec (s, va_alist) fputs (".\n", stderr); exit (1); } + +/* arch-tag: ce26be27-370a-438d-83b4-766059749a02 + (do not change this comment) */ diff --git a/src/unexhp9k800.c b/src/unexhp9k800.c index 0948ccf9a18..146cc5707da 100644 --- a/src/unexhp9k800.c +++ b/src/unexhp9k800.c @@ -317,3 +317,6 @@ display_header (hdr, auxhdr) hdr->unloadable_sp_location, hdr->unloadable_sp_size); } #endif /* DEBUG */ + +/* arch-tag: d55a09ac-9427-4ec4-8496-cb9d7710774f + (do not change this comment) */ diff --git a/src/unexmacosx.c b/src/unexmacosx.c index c84e5c95d03..b41c586d2e0 100644 --- a/src/unexmacosx.c +++ b/src/unexmacosx.c @@ -95,6 +95,10 @@ Boston, MA 02111-1307, USA. */ #include <unistd.h> #include <mach/mach.h> #include <mach-o/loader.h> +#include <mach-o/reloc.h> +#if defined (__ppc__) +#include <mach-o/ppc/reloc.h> +#endif #include <objc/malloc.h> #define VERBOSE 1 @@ -158,6 +162,11 @@ int in_dumped_exec = 0; malloc_zone_t *emacs_zone; +/* file offset of input file's data segment */ +off_t data_segment_old_fileoff; + +struct segment_command *data_segment_scp; + /* Read n bytes from infd into memory starting at address dest. Return true if successful, false otherwise. */ static int @@ -183,6 +192,7 @@ static int unexec_copy (off_t dest, off_t src, ssize_t count) { ssize_t bytes_read; + ssize_t bytes_to_read; char buf[UNEXEC_COPY_BUFSZ]; @@ -194,7 +204,8 @@ unexec_copy (off_t dest, off_t src, ssize_t count) while (count > 0) { - bytes_read = read (infd, buf, UNEXEC_COPY_BUFSZ); + bytes_to_read = count > UNEXEC_COPY_BUFSZ ? UNEXEC_COPY_BUFSZ : count; + bytes_read = read (infd, buf, bytes_to_read); if (bytes_read <= 0) return 0; if (write (outfd, buf, bytes_read) != bytes_read) @@ -763,6 +774,65 @@ copy_symtab (struct load_command *lc) curr_header_offset += lc->cmdsize; } +/* Fix up relocation entries. */ +static void +unrelocate (const char *name, off_t reloff, int nrel) +{ + int i, unreloc_count; + struct relocation_info reloc_info; + struct scattered_relocation_info *sc_reloc_info + = (struct scattered_relocation_info *) &reloc_info; + + for (unreloc_count = 0, i = 0; i < nrel; i++) + { + if (lseek (infd, reloff, L_SET) != reloff) + unexec_error ("unrelocate: %s:%d cannot seek to reloc_info", name, i); + if (!unexec_read (&reloc_info, sizeof (reloc_info))) + unexec_error ("unrelocate: %s:%d cannot read reloc_info", name, i); + reloff += sizeof (reloc_info); + + if (sc_reloc_info->r_scattered == 0) + switch (reloc_info.r_type) + { + case GENERIC_RELOC_VANILLA: + if (reloc_info.r_address >= data_segment_scp->vmaddr + && reloc_info.r_address < (data_segment_scp->vmaddr + + data_segment_scp->vmsize)) + { + off_t src_off = data_segment_old_fileoff + + reloc_info.r_address - data_segment_scp->vmaddr; + off_t dst_off = data_segment_scp->fileoff + + reloc_info.r_address - data_segment_scp->vmaddr; + + if (!unexec_copy (dst_off, src_off, 1 << reloc_info.r_length)) + unexec_error ("unrelocate: %s:%d cannot copy original value", + name, i); + unreloc_count++; + } + break; + default: + unexec_error ("unrelocate: %s:%d cannot handle type = %d", + name, i, reloc_info.r_type); + } + else + switch (sc_reloc_info->r_type) + { +#if defined (__ppc__) + case PPC_RELOC_PB_LA_PTR: + /* nothing to do for prebound lazy pointer */ + break; +#endif + default: + unexec_error ("unrelocate: %s:%d cannot handle scattered type = %d", + name, i, sc_reloc_info->r_type); + } + } + + if (nrel > 0) + printf ("Fixed up %d/%d %s relocation entries in data segment.\n", + unreloc_count, nrel, name); +} + /* Copy a LC_DYSYMTAB load command from the input file to the output file, adjusting the file offset fields. */ static void @@ -770,10 +840,8 @@ copy_dysymtab (struct load_command *lc) { struct dysymtab_command *dstp = (struct dysymtab_command *) lc; - /* If Mach-O executable is not prebound, relocation entries need - fixing up. This is not supported currently. */ - if (!(mh.flags & MH_PREBOUND) && (dstp->nextrel != 0 || dstp->nlocrel != 0)) - unexec_error ("cannot handle LC_DYSYMTAB with relocation entries"); + unrelocate ("local", dstp->locreloff, dstp->nlocrel); + unrelocate ("external", dstp->extreloff, dstp->nextrel); if (dstp->nextrel > 0) { dstp->extreloff += delta; @@ -845,6 +913,11 @@ dump_it () struct segment_command *scp = (struct segment_command *) lca[i]; if (strncmp (scp->segname, SEG_DATA, 16) == 0) { + /* save data segment file offset and segment_command for + unrelocate */ + data_segment_old_fileoff = scp->fileoff; + data_segment_scp = scp; + copy_data_segment (lca[i]); } else @@ -976,3 +1049,6 @@ unexec_free (void *ptr) else malloc_zone_free (emacs_zone, ptr); } + +/* arch-tag: 1a784f7b-a184-4c4f-9544-da8619593d72 + (do not change this comment) */ diff --git a/src/unexmips.c b/src/unexmips.c index cad42a17897..de3368ad181 100644 --- a/src/unexmips.c +++ b/src/unexmips.c @@ -359,3 +359,6 @@ fatal_unexec (s, va_alist) fputs (".\n", stderr); exit (1); } + +/* arch-tag: ebdd2058-3bbc-4de4-b5c7-5760379ab153 + (do not change this comment) */ diff --git a/src/unexnext.c b/src/unexnext.c index 649d0e0226f..50a0448d7bc 100644 --- a/src/unexnext.c +++ b/src/unexnext.c @@ -510,3 +510,6 @@ unexec( exit(1); } } + +/* arch-tag: 9796bdc3-c050-417a-b2f5-4cfd31032634 + (do not change this comment) */ diff --git a/src/unexsni.c b/src/unexsni.c index c9abec07e17..a99d51bc0cf 100644 --- a/src/unexsni.c +++ b/src/unexsni.c @@ -919,3 +919,6 @@ unexec (new_name, old_name, data_start, bss_start, entry_address) if (chmod (new_name, stat_buf.st_mode) == -1) fatal ("Can't chmod(%s): errno %d\n", new_name, errno); } + +/* arch-tag: c784ead3-7a27-442b-83fe-7af8d08654d3 + (do not change this comment) */ diff --git a/src/unexsol.c b/src/unexsol.c index 382682e4521..426a7f7cb99 100644 --- a/src/unexsol.c +++ b/src/unexsol.c @@ -27,3 +27,6 @@ unexec (char *new_name, char *old_name, unsigned int data_start, Fsignal (Qfile_error, Fcons (build_string ("Cannot unexec"), Fcons (errstring, data))); } + +/* arch-tag: d8ff72b3-8198-4011-8ef5-011b12027f59 + (do not change this comment) */ diff --git a/src/unexsunos4.c b/src/unexsunos4.c index 6ceab884a99..4534a32c322 100644 --- a/src/unexsunos4.c +++ b/src/unexsunos4.c @@ -375,3 +375,6 @@ is_it (filename) } return 0; } + +/* arch-tag: 30227420-2c6f-4700-a4f8-9e45e52f53b1 + (do not change this comment) */ diff --git a/src/unexw32.c b/src/unexw32.c index ece35459d63..b1838644965 100644 --- a/src/unexw32.c +++ b/src/unexw32.c @@ -807,3 +807,6 @@ unexec (char *new_name, char *old_name, void *start_data, void *start_bss, } /* eof */ + +/* arch-tag: fe1d3d1c-ef88-4917-ab22-f12ab16b3254 + (do not change this comment) */ diff --git a/src/vlimit.h b/src/vlimit.h index c347dc74df6..5885bee8d2d 100644 --- a/src/vlimit.h +++ b/src/vlimit.h @@ -1,2 +1,5 @@ /* Dummy for Emacs so that we can run on VMS... */ #define LIM_DATA 0 + +/* arch-tag: 0c3436cb-5edc-447a-87af-acec402a65b9 + (do not change this comment) */ diff --git a/src/vm-limit.c b/src/vm-limit.c index c0bab2e48a4..0dc89098afb 100644 --- a/src/vm-limit.c +++ b/src/vm-limit.c @@ -145,3 +145,6 @@ memory_warnings (start, warnfun) lim_data = 0; #endif } + +/* arch-tag: eab04eda-1f69-447a-8d9f-95f0a3983ca5 + (do not change this comment) */ diff --git a/src/w16select.c b/src/w16select.c index 199f4363a60..f765b5c55fc 100644 --- a/src/w16select.c +++ b/src/w16select.c @@ -764,3 +764,6 @@ set to nil. */); } #endif /* MSDOS */ + +/* arch-tag: 085a22c8-7324-436e-a6da-102464ce95d8 + (do not change this comment) */ diff --git a/src/w32.c b/src/w32.c index 744cc593133..98d630529e6 100644 --- a/src/w32.c +++ b/src/w32.c @@ -66,6 +66,7 @@ Boston, MA 02111-1307, USA. #include "lisp.h" #include <pwd.h> +#include <grp.h> #ifdef __GNUC__ #define _ANONYMOUS_UNION @@ -385,6 +386,13 @@ static struct passwd the_passwd = the_passwd_shell, }; +static struct group the_group = +{ + /* There are no groups on NT, so we just return "root" as the + group name. */ + "root", +}; + int getuid () { @@ -420,6 +428,12 @@ getpwuid (int uid) return NULL; } +struct group * +getgrgid (gid_t gid) +{ + return &the_group; +} + struct passwd * getpwnam (char *name) { @@ -3450,11 +3464,22 @@ sys_pipe (int * phandles) if (rc == 0) { - flags = FILE_PIPE | FILE_READ | FILE_BINARY; - fd_info[phandles[0]].flags = flags; + /* Protect against overflow, since Windows can open more handles than + our fd_info array has room for. */ + if (phandles[0] >= MAXDESC || phandles[1] >= MAXDESC) + { + _close (phandles[0]); + _close (phandles[1]); + rc = -1; + } + else + { + flags = FILE_PIPE | FILE_READ | FILE_BINARY; + fd_info[phandles[0]].flags = flags; - flags = FILE_PIPE | FILE_WRITE | FILE_BINARY; - fd_info[phandles[1]].flags = flags; + flags = FILE_PIPE | FILE_WRITE | FILE_BINARY; + fd_info[phandles[1]].flags = flags; + } } return rc; @@ -3955,3 +3980,6 @@ void globals_of_w32 () } /* end of nt.c */ + +/* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1 + (do not change this comment) */ diff --git a/src/w32.h b/src/w32.h index 845aca26e30..cce1f094363 100644 --- a/src/w32.h +++ b/src/w32.h @@ -134,3 +134,6 @@ extern void globals_of_w32menu (); extern void syms_of_fontset (); #endif /* EMACS_W32_H */ + +/* arch-tag: 02c36b00-312b-4c4d-a1d9-f905c5e968f0 + (do not change this comment) */ diff --git a/src/w32bdf.c b/src/w32bdf.c index 256310d2d35..a028d51d85a 100644 --- a/src/w32bdf.c +++ b/src/w32bdf.c @@ -247,7 +247,7 @@ w32_init_bdf_font(char *filename) hbdf_bmp_heap = HeapCreate(0, BDF_BITMAP_HEAP_INITIAL_SIZE, 0); if (!hbdf_cp_heap || !hbdf_bmp_heap) - error("Fail to create heap for BDF."); + error("Fail to create heap for BDF"); hfile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); @@ -257,13 +257,13 @@ w32_init_bdf_font(char *filename) (fileinfo.nFileSizeLow > BDF_FILE_SIZE_MAX)) { CloseHandle(hfile); - error("Fail to open BDF file."); + error("Fail to open BDF file"); } hfilemap = CreateFileMapping(hfile, NULL, PAGE_READONLY, 0, 0, NULL); if (hfilemap == INVALID_HANDLE_VALUE) { CloseHandle(hfile); - error("Can't map font."); + error("Can't map font"); } font = MapViewOfFile(hfilemap, FILE_MAP_READ, 0, 0, 0); @@ -272,7 +272,7 @@ w32_init_bdf_font(char *filename) { CloseHandle(hfile); CloseHandle(hfilemap); - error("Can't view font."); + error("Can't view font"); } bdffontp = (bdffont *) xmalloc(sizeof(bdffont)); @@ -867,3 +867,6 @@ int w32_BDF_to_x_font (char *file, char* xstr, int len) CloseHandle (hfilemap); return retval; } + +/* arch-tag: 2e9a45de-0c54-4a0e-95c8-2d67b2b1fa32 + (do not change this comment) */ diff --git a/src/w32bdf.h b/src/w32bdf.h index 1786786b90b..23939bfd7d8 100644 --- a/src/w32bdf.h +++ b/src/w32bdf.h @@ -124,3 +124,6 @@ int w32_BDF_TextOut (bdffont *fontp, HDC hdc, int left, int w32_BDF_to_x_font (char *file, char* xstr, int len); #endif /* EMACS_W32BDF_H */ + +/* arch-tag: 7499e9f2-197e-44cc-9274-373f00b51eec + (do not change this comment) */ diff --git a/src/w32console.c b/src/w32console.c index 61b142db028..50cbfb281d3 100644 --- a/src/w32console.c +++ b/src/w32console.c @@ -723,3 +723,6 @@ scroll-back buffer. */); defsubr (&Sset_cursor_size); defsubr (&Sset_message_beep); } + +/* arch-tag: a390a07f-f661-42bc-aeb4-e6d8bf860337 + (do not change this comment) */ diff --git a/src/w32fns.c b/src/w32fns.c index 5d6e88b62ce..ebdf5c3ccca 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -52,13 +52,13 @@ Boston, MA 02111-1307, USA. */ #include <commdlg.h> #include <shellapi.h> #include <ctype.h> +#include <winspool.h> #include <dlgs.h> #define FILE_NAME_TEXT_FIELD edt1 void syms_of_w32fns (); void globals_of_w32fns (); -static void init_external_image_libraries (); extern void free_frame_menubar (); extern double atof (); @@ -171,10 +171,6 @@ Lisp_Object Vx_cursor_fore_pixel; static int w32_in_use; -/* Search path for bitmap files. */ - -Lisp_Object Vx_bitmap_file_path; - /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */ Lisp_Object Vx_pixel_size_width_font_regexp; @@ -200,7 +196,6 @@ Lisp_Object Vw32_charset_info_alist; Lisp_Object Qnone; Lisp_Object Qsuppress_icon; Lisp_Object Qundefined_color; -Lisp_Object Qcenter; Lisp_Object Qcancel_timer; Lisp_Object Qhyper; Lisp_Object Qsuper; @@ -396,225 +391,6 @@ x_window_to_frame (dpyinfo, wdesc) } - -/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap - id, which is just an int that this section returns. Bitmaps are - reference counted so they can be shared among frames. - - Bitmap indices are guaranteed to be > 0, so a negative number can - be used to indicate no bitmap. - - If you use x_create_bitmap_from_data, then you must keep track of - the bitmaps yourself. That is, creating a bitmap from the same - data more than once will not be caught. */ - - -/* Functions to access the contents of a bitmap, given an id. */ - -int -x_bitmap_height (f, id) - FRAME_PTR f; - int id; -{ - return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height; -} - -int -x_bitmap_width (f, id) - FRAME_PTR f; - int id; -{ - return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width; -} - -int -x_bitmap_pixmap (f, id) - FRAME_PTR f; - int id; -{ - return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap; -} - - -/* Allocate a new bitmap record. Returns index of new record. */ - -static int -x_allocate_bitmap_record (f) - FRAME_PTR f; -{ - struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f); - int i; - - if (dpyinfo->bitmaps == NULL) - { - dpyinfo->bitmaps_size = 10; - dpyinfo->bitmaps - = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record)); - dpyinfo->bitmaps_last = 1; - return 1; - } - - if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size) - return ++dpyinfo->bitmaps_last; - - for (i = 0; i < dpyinfo->bitmaps_size; ++i) - if (dpyinfo->bitmaps[i].refcount == 0) - return i + 1; - - dpyinfo->bitmaps_size *= 2; - dpyinfo->bitmaps - = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps, - dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record)); - return ++dpyinfo->bitmaps_last; -} - -/* Add one reference to the reference count of the bitmap with id ID. */ - -void -x_reference_bitmap (f, id) - FRAME_PTR f; - int id; -{ - ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount; -} - -/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */ - -int -x_create_bitmap_from_data (f, bits, width, height) - struct frame *f; - char *bits; - unsigned int width, height; -{ - struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f); - Pixmap bitmap; - int id; - - bitmap = CreateBitmap (width, height, - FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes, - FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits, - bits); - - if (! bitmap) - return -1; - - id = x_allocate_bitmap_record (f); - dpyinfo->bitmaps[id - 1].pixmap = bitmap; - dpyinfo->bitmaps[id - 1].file = NULL; - dpyinfo->bitmaps[id - 1].hinst = NULL; - dpyinfo->bitmaps[id - 1].refcount = 1; - dpyinfo->bitmaps[id - 1].depth = 1; - dpyinfo->bitmaps[id - 1].height = height; - dpyinfo->bitmaps[id - 1].width = width; - - return id; -} - -/* Create bitmap from file FILE for frame F. */ - -int -x_create_bitmap_from_file (f, file) - struct frame *f; - Lisp_Object file; -{ - return -1; -#if 0 /* TODO : bitmap support */ - struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f); - unsigned int width, height; - HBITMAP bitmap; - int xhot, yhot, result, id; - Lisp_Object found; - int fd; - char *filename; - HINSTANCE hinst; - - /* Look for an existing bitmap with the same name. */ - for (id = 0; id < dpyinfo->bitmaps_last; ++id) - { - if (dpyinfo->bitmaps[id].refcount - && dpyinfo->bitmaps[id].file - && !strcmp (dpyinfo->bitmaps[id].file, (char *) SDATA (file))) - { - ++dpyinfo->bitmaps[id].refcount; - return id + 1; - } - } - - /* Search bitmap-file-path for the file, if appropriate. */ - fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil); - if (fd < 0) - return -1; - emacs_close (fd); - - filename = (char *) SDATA (found); - - hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE); - - if (hinst == NULL) - return -1; - - - result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), - filename, &width, &height, &bitmap, &xhot, &yhot); - if (result != BitmapSuccess) - return -1; - - id = x_allocate_bitmap_record (f); - dpyinfo->bitmaps[id - 1].pixmap = bitmap; - dpyinfo->bitmaps[id - 1].refcount = 1; - dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (SCHARS (file) + 1); - dpyinfo->bitmaps[id - 1].depth = 1; - dpyinfo->bitmaps[id - 1].height = height; - dpyinfo->bitmaps[id - 1].width = width; - strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file)); - - return id; -#endif /* TODO */ -} - -/* Remove reference to bitmap with id number ID. */ - -void -x_destroy_bitmap (f, id) - FRAME_PTR f; - int id; -{ - struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f); - - if (id > 0) - { - --dpyinfo->bitmaps[id - 1].refcount; - if (dpyinfo->bitmaps[id - 1].refcount == 0) - { - BLOCK_INPUT; - DeleteObject (dpyinfo->bitmaps[id - 1].pixmap); - if (dpyinfo->bitmaps[id - 1].file) - { - xfree (dpyinfo->bitmaps[id - 1].file); - dpyinfo->bitmaps[id - 1].file = NULL; - } - UNBLOCK_INPUT; - } - } -} - -/* Free all the bitmaps for the display specified by DPYINFO. */ - -static void -x_destroy_all_bitmaps (dpyinfo) - struct w32_display_info *dpyinfo; -{ - int i; - for (i = 0; i < dpyinfo->bitmaps_last; i++) - if (dpyinfo->bitmaps[i].refcount > 0) - { - DeleteObject (dpyinfo->bitmaps[i].pixmap); - if (dpyinfo->bitmaps[i].file) - xfree (dpyinfo->bitmaps[i].file); - } - dpyinfo->bitmaps_last = 0; -} - BOOL my_show_window P_ ((struct frame *, HWND, int)); void my_set_window_pos P_ ((HWND, HWND, int, int, int, int, UINT)); static Lisp_Object unwind_create_frame P_ ((Lisp_Object)); @@ -5618,6 +5394,10 @@ x_to_w32_font (lpxstr, lplogfont) coding.dst_multibyte = 1; coding.dst_bytes = strlen (name) * 2; coding.destination = (unsigned char *) xmalloc (coding.dst_bytes); + /* Disable composition/charset annotation. */ + coding.common_flags &= ~CODING_ANNOTATION_MASK; + if (coding.type == coding_type_iso2022) + coding.flags |= CODING_FLAG_ISO_SAFE; coding.mode |= CODING_MODE_LAST_BLOCK; encode_coding_object (&coding, build_string (name), 0, 0, strlen (name), coding.dst_bytes, Qnil); @@ -6987,5480 +6767,6 @@ DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0, return Qnil; } - -/*********************************************************************** - Image types - ***********************************************************************/ - -/* Value is the number of elements of vector VECTOR. */ - -#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR)) - -/* List of supported image types. Use define_image_type to add new - types. Use lookup_image_type to find a type for a given symbol. */ - -static struct image_type *image_types; - -/* The symbol `image' which is the car of the lists used to represent - images in Lisp. */ - -extern Lisp_Object Qimage; - -/* The symbol `xbm' which is used as the type symbol for XBM images. */ - -Lisp_Object Qxbm; - -/* Keywords. */ - -extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile; -extern Lisp_Object QCdata, QCtype; -Lisp_Object QCascent, QCmargin, QCrelief; -Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask; -Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask; - -/* Other symbols. */ - -Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic; - -/* Time in seconds after which images should be removed from the cache - if not displayed. */ - -Lisp_Object Vimage_cache_eviction_delay; - -/* Function prototypes. */ - -static void define_image_type P_ ((struct image_type *type)); -static struct image_type *lookup_image_type P_ ((Lisp_Object symbol)); -static void image_error P_ ((char *format, Lisp_Object, Lisp_Object)); -static void x_laplace P_ ((struct frame *, struct image *)); -static void x_emboss P_ ((struct frame *, struct image *)); -static int x_build_heuristic_mask P_ ((struct frame *, struct image *, - Lisp_Object)); - - -/* Define a new image type from TYPE. This adds a copy of TYPE to - image_types and adds the symbol *TYPE->type to Vimage_types. */ - -static void -define_image_type (type) - struct image_type *type; -{ - /* Make a copy of TYPE to avoid a bus error in a dumped Emacs. - The initialized data segment is read-only. */ - struct image_type *p = (struct image_type *) xmalloc (sizeof *p); - bcopy (type, p, sizeof *p); - p->next = image_types; - image_types = p; - Vimage_types = Fcons (*p->type, Vimage_types); -} - - -/* Look up image type SYMBOL, and return a pointer to its image_type - structure. Value is null if SYMBOL is not a known image type. */ - -static INLINE struct image_type * -lookup_image_type (symbol) - Lisp_Object symbol; -{ - struct image_type *type; - - for (type = image_types; type; type = type->next) - if (EQ (symbol, *type->type)) - break; - - return type; -} - - -/* Value is non-zero if OBJECT is a valid Lisp image specification. A - valid image specification is a list whose car is the symbol - `image', and whose rest is a property list. The property list must - contain a value for key `:type'. That value must be the name of a - supported image type. The rest of the property list depends on the - image type. */ - -int -valid_image_p (object) - Lisp_Object object; -{ - int valid_p = 0; - - if (CONSP (object) && EQ (XCAR (object), Qimage)) - { - 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; -} - - -/* Log error message with format string FORMAT and argument ARG. - Signaling an error, e.g. when an image cannot be loaded, is not a - good idea because this would interrupt redisplay, and the error - message display would lead to another redisplay. This function - therefore simply displays a message. */ - -static void -image_error (format, arg1, arg2) - char *format; - Lisp_Object arg1, arg2; -{ - add_to_log (format, arg1, arg2); -} - - - -/*********************************************************************** - Image specifications - ***********************************************************************/ - -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, - IMAGE_FUNCTION_VALUE, - IMAGE_NUMBER_VALUE, - IMAGE_BOOL_VALUE -}; - -/* Structure used when parsing image specifications. */ - -struct image_keyword -{ - /* Name of keyword. */ - char *name; - - /* The type of value allowed. */ - enum image_value_type type; - - /* Non-zero means key must be present. */ - int mandatory_p; - - /* Used to recognize duplicate keywords in a property list. */ - int count; - - /* The value that was found. */ - Lisp_Object value; -}; - - -static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *, - int, Lisp_Object)); -static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *)); - - -/* Parse image spec SPEC according to KEYWORDS. A valid image spec - has the format (image KEYWORD VALUE ...). One of the keyword/ - value pairs must be `:type TYPE'. KEYWORDS is a vector of - image_keywords structures of size NKEYWORDS describing other - allowed keyword/value pairs. Value is non-zero if SPEC is valid. */ - -static int -parse_image_spec (spec, keywords, nkeywords, type) - Lisp_Object spec; - struct image_keyword *keywords; - int nkeywords; - Lisp_Object type; -{ - int i; - Lisp_Object plist; - - if (!CONSP (spec) || !EQ (XCAR (spec), Qimage)) - return 0; - - plist = XCDR (spec); - while (CONSP (plist)) - { - Lisp_Object key, value; - - /* First element of a pair must be a symbol. */ - key = XCAR (plist); - plist = XCDR (plist); - if (!SYMBOLP (key)) - return 0; - - /* There must follow a value. */ - if (!CONSP (plist)) - return 0; - value = XCAR (plist); - plist = XCDR (plist); - - /* Find key in KEYWORDS. Error if not found. */ - for (i = 0; i < nkeywords; ++i) - if (strcmp (keywords[i].name, SDATA (SYMBOL_NAME (key))) == 0) - break; - - if (i == nkeywords) - continue; - - /* Record that we recognized the keyword. If a keywords - was found more than once, it's an error. */ - keywords[i].value = value; - ++keywords[i].count; - - if (keywords[i].count > 1) - return 0; - - /* Check type of value against allowed type. */ - switch (keywords[i].type) - { - case IMAGE_STRING_VALUE: - if (!STRINGP (value)) - 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; - break; - - case IMAGE_POSITIVE_INTEGER_VALUE: - if (!INTEGERP (value) || XINT (value) <= 0) - 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; - else if (INTEGERP (value) - && XINT (value) >= 0 - && XINT (value) <= 100) - break; - return 0; - - case IMAGE_NON_NEGATIVE_INTEGER_VALUE: - if (!INTEGERP (value) || XINT (value) < 0) - return 0; - break; - - case IMAGE_DONT_CHECK_VALUE_TYPE: - break; - - case IMAGE_FUNCTION_VALUE: - value = indirect_function (value); - if (SUBRP (value) - || COMPILEDP (value) - || (CONSP (value) && EQ (XCAR (value), Qlambda))) - break; - return 0; - - case IMAGE_NUMBER_VALUE: - if (!INTEGERP (value) && !FLOATP (value)) - return 0; - break; - - case IMAGE_INTEGER_VALUE: - if (!INTEGERP (value)) - return 0; - break; - - case IMAGE_BOOL_VALUE: - if (!NILP (value) && !EQ (value, Qt)) - return 0; - break; - - default: - abort (); - break; - } - - if (EQ (key, QCtype) && !EQ (type, value)) - return 0; - } - - /* Check that all mandatory fields are present. */ - for (i = 0; i < nkeywords; ++i) - if (keywords[i].mandatory_p && keywords[i].count == 0) - return 0; - - return NILP (plist); -} - - -/* Return the value of KEY in image specification SPEC. Value is nil - if KEY is not present in SPEC. if FOUND is not null, set *FOUND - to 1 if KEY was found in SPEC, set it to 0 otherwise. */ - -static Lisp_Object -image_spec_value (spec, key, found) - Lisp_Object spec, key; - int *found; -{ - Lisp_Object tail; - - xassert (valid_image_p (spec)); - - for (tail = XCDR (spec); - CONSP (tail) && CONSP (XCDR (tail)); - tail = XCDR (XCDR (tail))) - { - if (EQ (XCAR (tail), key)) - { - if (found) - *found = 1; - return XCAR (XCDR (tail)); - } - } - - if (found) - *found = 0; - return Qnil; -} - - -DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0, - doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT). -PIXELS non-nil means return the size in pixels, otherwise return the -size in canonical character units. -FRAME is the frame on which the image will be displayed. FRAME nil -or omitted means use the selected frame. */) - (spec, pixels, frame) - Lisp_Object spec, pixels, frame; -{ - Lisp_Object size; - - size = Qnil; - if (valid_image_p (spec)) - { - 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->hmargin; - int height = img->height + 2 * img->vmargin; - - if (NILP (pixels)) - size = Fcons (make_float ((double) width / FRAME_COLUMN_WIDTH (f)), - make_float ((double) height / FRAME_LINE_HEIGHT (f))); - else - size = Fcons (make_number (width), make_number (height)); - } - else - error ("Invalid image specification"); - - return size; -} - - -DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0, - doc: /* Return t if image SPEC has a mask bitmap. -FRAME is the frame on which the image will be displayed. FRAME nil -or omitted means use the selected frame. */) - (spec, frame) - Lisp_Object spec, frame; -{ - Lisp_Object mask; - - mask = Qnil; - if (valid_image_p (spec)) - { - struct frame *f = check_x_frame (frame); - int id = lookup_image (f, spec); - struct image *img = IMAGE_FROM_ID (f, id); - if (img->mask) - mask = Qt; - } - else - error ("Invalid image specification"); - - return mask; -} - - -/*********************************************************************** - Image type independent image structures - ***********************************************************************/ - -static struct image *make_image P_ ((Lisp_Object spec, unsigned hash)); -static void free_image P_ ((struct frame *f, struct image *img)); -static void x_destroy_x_image P_ ((XImage *)); - - -/* Allocate and return a new image structure for image specification - SPEC. SPEC has a hash value of HASH. */ - -static struct image * -make_image (spec, hash) - Lisp_Object spec; - unsigned hash; -{ - struct image *img = (struct image *) xmalloc (sizeof *img); - - xassert (valid_image_p (spec)); - bzero (img, sizeof *img); - img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL)); - xassert (img->type != NULL); - img->spec = spec; - img->data.lisp_val = Qnil; - img->ascent = DEFAULT_IMAGE_ASCENT; - img->hash = hash; - return img; -} - - -/* Free image IMG which was used on frame F, including its resources. */ - -static void -free_image (f, img) - struct frame *f; - struct image *img; -{ - if (img) - { - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - - /* Remove IMG from the hash table of its cache. */ - if (img->prev) - img->prev->next = img->next; - else - c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next; - - if (img->next) - img->next->prev = img->prev; - - c->images[img->id] = NULL; - - /* Free resources, then free IMG. */ - img->type->free (f, img); - xfree (img); - } -} - - -/* Prepare image IMG for display on frame F. Must be called before - drawing an image. */ - -void -prepare_image_for_display (f, img) - struct frame *f; - struct image *img; -{ - EMACS_TIME t; - - /* We're about to display IMG, so set its timestamp to `now'. */ - EMACS_GET_TIME (t); - img->timestamp = EMACS_SECS (t); - - /* If IMG doesn't have a pixmap yet, load it now, using the image - type dependent loader function. */ - if (img->pixmap == 0 && !img->load_failed_p) - img->load_failed_p = img->type->load (f, img) == 0; -} - - -/* Value is the number of pixels for the ascent of image IMG when - drawn in face FACE. */ - -int -image_ascent (img, face) - struct image *img; - struct face *face; -{ - int height = img->height + img->vmargin; - int ascent; - - if (img->ascent == CENTERED_IMAGE_ASCENT) - { - if (face->font) - ascent = height / 2 - (FONT_DESCENT(face->font) - - FONT_BASE(face->font)) / 2; - else - ascent = height / 2; - } - else - ascent = (int) (height * img->ascent / 100.0); - - return ascent; -} - - - -/* Image background colors. */ - -/* Find the "best" corner color of a bitmap. XIMG is assumed to a device - context with the bitmap selected. */ -static COLORREF -four_corners_best (img_dc, width, height) - HDC img_dc; - unsigned long width, height; -{ - COLORREF corners[4], best; - int i, best_count; - - /* Get the colors at the corners of img_dc. */ - corners[0] = GetPixel (img_dc, 0, 0); - corners[1] = GetPixel (img_dc, width - 1, 0); - corners[2] = GetPixel (img_dc, width - 1, height - 1); - corners[3] = GetPixel (img_dc, 0, height - 1); - - /* Choose the most frequently found color as background. */ - for (i = best_count = 0; i < 4; ++i) - { - int j, n; - - for (j = n = 0; j < 4; ++j) - if (corners[i] == corners[j]) - ++n; - - if (n > best_count) - best = corners[i], best_count = n; - } - - return best; -} - -/* Return the `background' field of IMG. If IMG doesn't have one yet, - it is guessed heuristically. If non-zero, IMG_DC is an existing - device context with the image selected to use for the heuristic. */ - -unsigned long -image_background (img, f, img_dc) - struct image *img; - struct frame *f; - HDC img_dc; -{ - if (! img->background_valid) - /* IMG doesn't have a background yet, try to guess a reasonable value. */ - { - int free_ximg = !img_dc; - HGDIOBJ prev; - - if (free_ximg) - { - HDC frame_dc = get_frame_dc (f); - img_dc = CreateCompatibleDC (frame_dc); - release_frame_dc (f, frame_dc); - - prev = SelectObject (img_dc, img->pixmap); - } - - img->background = four_corners_best (img_dc, img->width, img->height); - - if (free_ximg) - { - SelectObject (img_dc, prev); - DeleteDC (img_dc); - } - - img->background_valid = 1; - } - - return img->background; -} - -/* Return the `background_transparent' field of IMG. If IMG doesn't - have one yet, it is guessed heuristically. If non-zero, MASK is an - existing XImage object to use for the heuristic. */ - -int -image_background_transparent (img, f, mask) - struct image *img; - struct frame *f; - HDC mask; -{ - if (! img->background_transparent_valid) - /* IMG doesn't have a background yet, try to guess a reasonable value. */ - { - if (img->mask) - { - int free_mask = !mask; - HGDIOBJ prev; - - if (free_mask) - { - HDC frame_dc = get_frame_dc (f); - mask = CreateCompatibleDC (frame_dc); - release_frame_dc (f, frame_dc); - - prev = SelectObject (mask, img->mask); - } - - img->background_transparent - = !four_corners_best (mask, img->width, img->height); - - if (free_mask) - { - SelectObject (mask, prev); - DeleteDC (mask); - } - } - else - img->background_transparent = 0; - - img->background_transparent_valid = 1; - } - - return img->background_transparent; -} - - -/*********************************************************************** - Helper functions for X image types - ***********************************************************************/ - -static void x_clear_image_1 P_ ((struct frame *, struct image *, int, - int, int)); -static void x_clear_image P_ ((struct frame *f, struct image *img)); -static unsigned long x_alloc_image_color P_ ((struct frame *f, - struct image *img, - Lisp_Object color_name, - unsigned long dflt)); - - -/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means - free the pixmap if any. MASK_P non-zero means clear the mask - pixmap if any. COLORS_P non-zero means free colors allocated for - the image, if any. */ - -static void -x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p) - struct frame *f; - struct image *img; - int pixmap_p, mask_p, colors_p; -{ - if (pixmap_p && img->pixmap) - { - DeleteObject (img->pixmap); - img->pixmap = NULL; - img->background_valid = 0; - } - - if (mask_p && img->mask) - { - DeleteObject (img->mask); - img->mask = NULL; - img->background_transparent_valid = 0; - } - - if (colors_p && img->ncolors) - { -#if 0 /* TODO: color table support. */ - x_free_colors (f, img->colors, img->ncolors); -#endif - xfree (img->colors); - img->colors = NULL; - img->ncolors = 0; - } -} - -/* Free X resources of image IMG which is used on frame F. */ - -static void -x_clear_image (f, img) - struct frame *f; - struct image *img; -{ - if (img->pixmap) - { - BLOCK_INPUT; - DeleteObject (img->pixmap); - img->pixmap = 0; - UNBLOCK_INPUT; - } - - if (img->ncolors) - { -#if 0 /* TODO: color table support */ - - int class = FRAME_W32_DISPLAY_INFO (f)->visual->class; - - /* If display has an immutable color map, freeing colors is not - necessary and some servers don't allow it. So don't do it. */ - if (class != StaticColor - && class != StaticGray - && class != TrueColor) - { - Colormap cmap; - BLOCK_INPUT; - cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen); - XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors, - img->ncolors, 0); - UNBLOCK_INPUT; - } -#endif - - xfree (img->colors); - img->colors = NULL; - img->ncolors = 0; - } -} - - -/* Allocate color COLOR_NAME for image IMG on frame F. If color - cannot be allocated, use DFLT. Add a newly allocated color to - IMG->colors, so that it can be freed again. Value is the pixel - color. */ - -static unsigned long -x_alloc_image_color (f, img, color_name, dflt) - struct frame *f; - struct image *img; - Lisp_Object color_name; - unsigned long dflt; -{ - XColor color; - unsigned long result; - - xassert (STRINGP (color_name)); - - if (w32_defined_color (f, SDATA (color_name), &color, 1)) - { - /* This isn't called frequently so we get away with simply - reallocating the color vector to the needed size, here. */ - ++img->ncolors; - img->colors = - (unsigned long *) xrealloc (img->colors, - img->ncolors * sizeof *img->colors); - img->colors[img->ncolors - 1] = color.pixel; - result = color.pixel; - } - else - result = dflt; - return result; -} - - - -/*********************************************************************** - Image Cache - ***********************************************************************/ - -static void cache_image P_ ((struct frame *f, struct image *img)); -static void postprocess_image P_ ((struct frame *, struct image *)); -static void x_disable_image P_ ((struct frame *, struct image *)); - - -/* Return a new, initialized image cache that is allocated from the - heap. Call free_image_cache to free an image cache. */ - -struct image_cache * -make_image_cache () -{ - struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c); - int size; - - bzero (c, sizeof *c); - c->size = 50; - c->images = (struct image **) xmalloc (c->size * sizeof *c->images); - size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets; - c->buckets = (struct image **) xmalloc (size); - bzero (c->buckets, size); - return c; -} - - -/* Free image cache of frame F. Be aware that X frames share images - caches. */ - -void -free_image_cache (f) - struct frame *f; -{ - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - if (c) - { - int i; - - /* Cache should not be referenced by any frame when freed. */ - xassert (c->refcount == 0); - - for (i = 0; i < c->used; ++i) - free_image (f, c->images[i]); - xfree (c->images); - xfree (c); - xfree (c->buckets); - FRAME_X_IMAGE_CACHE (f) = NULL; - } -} - - -/* Clear image cache of frame F. FORCE_P non-zero means free all - images. FORCE_P zero means clear only images that haven't been - displayed for some time. Should be called from time to time to - reduce the number of loaded images. If image-eviction-seconds is - non-nil, this frees images in the cache which weren't displayed for - at least that many seconds. */ - -void -clear_image_cache (f, force_p) - struct frame *f; - int force_p; -{ - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - - if (c && INTEGERP (Vimage_cache_eviction_delay)) - { - EMACS_TIME t; - unsigned long old; - int i, nfreed; - - EMACS_GET_TIME (t); - old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay); - - /* Block input so that we won't be interrupted by a SIGIO - while being in an inconsistent state. */ - BLOCK_INPUT; - - for (i = nfreed = 0; i < c->used; ++i) - { - struct image *img = c->images[i]; - if (img != NULL - && (force_p || (img->timestamp < old))) - { - free_image (f, img); - ++nfreed; - } - } - - /* We may be clearing the image cache because, for example, - Emacs was iconified for a longer period of time. In that - case, current matrices may still contain references to - images freed above. So, clear these matrices. */ - if (nfreed) - { - Lisp_Object tail, frame; - - FOR_EACH_FRAME (tail, frame) - { - struct frame *f = XFRAME (frame); - if (FRAME_W32_P (f) - && FRAME_X_IMAGE_CACHE (f) == c) - clear_current_matrices (f); - } - - ++windows_or_buffers_changed; - } - - UNBLOCK_INPUT; - } -} - - -DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache, - 0, 1, 0, - doc: /* Clear the image cache of FRAME. -FRAME nil or omitted means use the selected frame. -FRAME t means clear the image caches of all frames. */) - (frame) - Lisp_Object frame; -{ - if (EQ (frame, Qt)) - { - Lisp_Object tail; - - FOR_EACH_FRAME (tail, frame) - if (FRAME_W32_P (XFRAME (frame))) - clear_image_cache (XFRAME (frame), 1); - } - else - clear_image_cache (check_x_frame (frame), 1); - - return Qnil; -} - - -/* 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) - { - DeleteObject (img->mask); - img->mask = NULL; - } - } - - - /* 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). */ - -int -lookup_image (f, spec) - struct frame *f; - Lisp_Object spec; -{ - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - struct image *img; - int i; - unsigned hash; - struct gcpro gcpro1; - EMACS_TIME now; - - /* F must be a window-system frame, and SPEC must be a valid image - specification. */ - xassert (FRAME_WINDOW_P (f)); - xassert (valid_image_p (spec)); - - GCPRO1 (spec); - - /* Look up SPEC in the hash table of the image cache. */ - hash = sxhash (spec, 0); - i = hash % IMAGE_CACHE_BUCKETS_SIZE; - - for (img = c->buckets[i]; img; img = img->next) - if (img->hash == hash && !NILP (Fequal (img->spec, spec))) - break; - - /* 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); - 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->load_failed_p) - { - Lisp_Object value; - - value = image_spec_value (spec, QCwidth, NULL); - img->width = (INTEGERP (value) - ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH); - value = image_spec_value (spec, QCheight, NULL); - img->height = (INTEGERP (value) - ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT); - } - else - { - /* Handle image type independent image attributes - `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF', - `:background COLOR'. */ - Lisp_Object ascent, margin, relief, bg; - - ascent = image_spec_value (spec, QCascent, NULL); - if (INTEGERP (ascent)) - img->ascent = XFASTINT (ascent); - else if (EQ (ascent, Qcenter)) - img->ascent = CENTERED_IMAGE_ASCENT; - - margin = image_spec_value (spec, QCmargin, NULL); - if (INTEGERP (margin) && XINT (margin) >= 0) - 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->hmargin += abs (img->relief); - img->vmargin += abs (img->relief); - } - - if (! img->background_valid) - { - bg = image_spec_value (img->spec, QCbackground, NULL); - if (!NILP (bg)) - { - img->background - = x_alloc_image_color (f, img, bg, - FRAME_BACKGROUND_PIXEL (f)); - img->background_valid = 1; - } - } - - /* Do image transformations and compute masks, unless we - don't have the image yet. */ - if (!EQ (*img->type->type, Qpostscript)) - postprocess_image (f, img); - } - - UNBLOCK_INPUT; - xassert (!interrupt_input_blocked); - } - - /* We're using IMG, so set its timestamp to `now'. */ - EMACS_GET_TIME (now); - img->timestamp = EMACS_SECS (now); - - UNGCPRO; - - /* Value is the image id. */ - return img->id; -} - - -/* Cache image IMG in the image cache of frame F. */ - -static void -cache_image (f, img) - struct frame *f; - struct image *img; -{ - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - int i; - - /* Find a free slot in c->images. */ - for (i = 0; i < c->used; ++i) - if (c->images[i] == NULL) - break; - - /* If no free slot found, maybe enlarge c->images. */ - if (i == c->used && c->used == c->size) - { - c->size *= 2; - c->images = (struct image **) xrealloc (c->images, - c->size * sizeof *c->images); - } - - /* Add IMG to c->images, and assign IMG an id. */ - c->images[i] = img; - img->id = i; - if (i == c->used) - ++c->used; - - /* Add IMG to the cache's hash table. */ - i = img->hash % IMAGE_CACHE_BUCKETS_SIZE; - img->next = c->buckets[i]; - if (img->next) - img->next->prev = img; - img->prev = NULL; - c->buckets[i] = img; -} - - -/* Call FN on every image in the image cache of frame F. Used to mark - Lisp Objects in the image cache. */ - -void -forall_images_in_image_cache (f, fn) - struct frame *f; - void (*fn) P_ ((struct image *img)); -{ - if (FRAME_LIVE_P (f) && FRAME_W32_P (f)) - { - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - if (c) - { - int i; - for (i = 0; i < c->used; ++i) - if (c->images[i]) - fn (c->images[i]); - } - } -} - - - -/*********************************************************************** - W32 support code - ***********************************************************************/ - -/* Macro for defining functions that will be loaded from image DLLs. */ -#define DEF_IMGLIB_FN(func) FARPROC fn_##func - -/* Macro for loading those image functions from the library. */ -#define LOAD_IMGLIB_FN(lib,func) { \ - fn_##func = (void *) GetProcAddress (lib, #func); \ - if (!fn_##func) return 0; \ - } - -static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int, - XImage **, Pixmap *)); -static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int)); - - -/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on - frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created. - Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated - via xmalloc. DEPTH of zero signifies a 24 bit image, otherwise - DEPTH should indicate the bit depth of the image. Print error - messages via image_error if an error occurs. Value is non-zero if - successful. */ - -static int -x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap) - struct frame *f; - int width, height, depth; - XImage **ximg; - Pixmap *pixmap; -{ - BITMAPINFOHEADER *header; - HDC hdc; - int scanline_width_bits; - int remainder; - int palette_colors = 0; - - if (depth == 0) - depth = 24; - - if (depth != 1 && depth != 4 && depth != 8 - && depth != 16 && depth != 24 && depth != 32) - { - image_error ("Invalid image bit depth specified", Qnil, Qnil); - return 0; - } - - scanline_width_bits = width * depth; - remainder = scanline_width_bits % 32; - - if (remainder) - scanline_width_bits += 32 - remainder; - - /* Bitmaps with a depth less than 16 need a palette. */ - /* BITMAPINFO structure already contains the first RGBQUAD. */ - if (depth < 16) - palette_colors = 1 << depth - 1; - - *ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD)); - if (*ximg == NULL) - { - image_error ("Unable to allocate memory for XImage", Qnil, Qnil); - return 0; - } - - header = &((*ximg)->info.bmiHeader); - bzero (&((*ximg)->info), sizeof (BITMAPINFO)); - header->biSize = sizeof (*header); - header->biWidth = width; - header->biHeight = -height; /* negative indicates a top-down bitmap. */ - header->biPlanes = 1; - header->biBitCount = depth; - header->biCompression = BI_RGB; - header->biClrUsed = palette_colors; - - /* TODO: fill in palette. */ - if (depth == 1) - { - (*ximg)->info.bmiColors[0].rgbBlue = 0; - (*ximg)->info.bmiColors[0].rgbGreen = 0; - (*ximg)->info.bmiColors[0].rgbRed = 0; - (*ximg)->info.bmiColors[0].rgbReserved = 0; - (*ximg)->info.bmiColors[1].rgbBlue = 255; - (*ximg)->info.bmiColors[1].rgbGreen = 255; - (*ximg)->info.bmiColors[1].rgbRed = 255; - (*ximg)->info.bmiColors[1].rgbReserved = 0; - } - - hdc = get_frame_dc (f); - - /* Create a DIBSection and raster array for the bitmap, - and store its handle in *pixmap. */ - *pixmap = CreateDIBSection (hdc, &((*ximg)->info), - (depth < 16) ? DIB_PAL_COLORS : DIB_RGB_COLORS, - &((*ximg)->data), NULL, 0); - - /* Realize display palette and garbage all frames. */ - release_frame_dc (f, hdc); - - if (*pixmap == NULL) - { - DWORD err = GetLastError(); - Lisp_Object errcode; - /* All system errors are < 10000, so the following is safe. */ - XSETINT (errcode, (int) err); - image_error ("Unable to create bitmap, error code %d", errcode, Qnil); - x_destroy_x_image (*ximg); - return 0; - } - - return 1; -} - - -/* Destroy XImage XIMG. Free XIMG->data. */ - -static void -x_destroy_x_image (ximg) - XImage *ximg; -{ - xassert (interrupt_input_blocked); - if (ximg) - { - /* Data will be freed by DestroyObject. */ - ximg->data = NULL; - xfree (ximg); - } -} - - -/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT - are width and height of both the image and pixmap. */ - -static void -x_put_x_image (f, ximg, pixmap, width, height) - struct frame *f; - XImage *ximg; - Pixmap pixmap; - int width, height; -{ -#if 0 /* I don't think this is necessary looking at where it is used. */ - HDC hdc = get_frame_dc (f); - SetDIBits (hdc, pixmap, 0, height, ximg->data, &(ximg->info), DIB_RGB_COLORS); - release_frame_dc (f, hdc); -#endif -} - - -/*********************************************************************** - File Handling - ***********************************************************************/ - -static Lisp_Object x_find_image_file P_ ((Lisp_Object)); -static char *slurp_file P_ ((char *, int *)); - - -/* Find image file FILE. Look in data-directory, then - x-bitmap-file-path. Value is the full name of the file found, or - nil if not found. */ - -static Lisp_Object -x_find_image_file (file) - Lisp_Object file; -{ - Lisp_Object file_found, search_path; - struct gcpro gcpro1, gcpro2; - int fd; - - file_found = Qnil; - search_path = Fcons (Vdata_directory, Vx_bitmap_file_path); - GCPRO2 (file_found, search_path); - - /* Try to find FILE in data-directory, then x-bitmap-file-path. */ - fd = openp (search_path, file, Qnil, &file_found, Qnil); - - if (fd == -1) - file_found = Qnil; - else - close (fd); - - UNGCPRO; - return file_found; -} - - -/* Read FILE into memory. Value is a pointer to a buffer allocated - with xmalloc holding FILE's contents. Value is null if an error - occurred. *SIZE is set to the size of the file. */ - -static char * -slurp_file (file, size) - char *file; - int *size; -{ - FILE *fp = NULL; - char *buf = NULL; - struct stat st; - - if (stat (file, &st) == 0 - && (fp = fopen (file, "rb")) != NULL - && (buf = (char *) xmalloc (st.st_size), - fread (buf, 1, st.st_size, fp) == st.st_size)) - { - *size = st.st_size; - fclose (fp); - } - else - { - if (fp) - fclose (fp); - if (buf) - { - xfree (buf); - buf = NULL; - } - } - - return buf; -} - - - -/*********************************************************************** - XBM images - ***********************************************************************/ - -static int xbm_scan P_ ((char **, char *, char *, int *)); -static int xbm_load P_ ((struct frame *f, struct image *img)); -static int xbm_load_image P_ ((struct frame *f, struct image *img, - char *, char *)); -static int xbm_image_p P_ ((Lisp_Object object)); -static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *, - unsigned char **)); -static int xbm_file_p P_ ((Lisp_Object)); - - -/* Indices of image specification fields in xbm_format, below. */ - -enum xbm_keyword_index -{ - XBM_TYPE, - XBM_FILE, - XBM_WIDTH, - XBM_HEIGHT, - XBM_DATA, - XBM_FOREGROUND, - XBM_BACKGROUND, - XBM_ASCENT, - XBM_MARGIN, - XBM_RELIEF, - XBM_ALGORITHM, - XBM_HEURISTIC_MASK, - XBM_MASK, - XBM_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid XBM image specifications. */ - -static struct image_keyword xbm_format[XBM_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":file", IMAGE_STRING_VALUE, 0}, - {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0}, - {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0}, - {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 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_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 0}, - {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} -}; - -/* Structure describing the image type XBM. */ - -static struct image_type xbm_type = -{ - &Qxbm, - xbm_image_p, - xbm_load, - x_clear_image, - NULL -}; - -/* Tokens returned from xbm_scan. */ - -enum xbm_token -{ - XBM_TK_IDENT = 256, - XBM_TK_NUMBER -}; - - -/* Return non-zero if OBJECT is a valid XBM-type image specification. - A valid specification is a list starting with the symbol `image' - The rest of the list is a property list which must contain an - entry `:type xbm.. - - If the specification specifies a file to load, it must contain - an entry `:file FILENAME' where FILENAME is a string. - - If the specification is for a bitmap loaded from memory it must - contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where - WIDTH and HEIGHT are integers > 0. DATA may be: - - 1. a string large enough to hold the bitmap data, i.e. it must - have a size >= (WIDTH + 7) / 8 * HEIGHT - - 2. a bool-vector of size >= WIDTH * HEIGHT - - 3. a vector of strings or bool-vectors, one for each line of the - bitmap. - - 4. A string containing an in-memory XBM file. WIDTH and HEIGHT - may not be specified in this case because they are defined in the - XBM file. - - Both the file and data forms may contain the additional entries - `:background COLOR' and `:foreground COLOR'. If not present, - foreground and background of the frame on which the image is - displayed is used. */ - -static int -xbm_image_p (object) - Lisp_Object object; -{ - struct image_keyword kw[XBM_LAST]; - - bcopy (xbm_format, kw, sizeof kw); - if (!parse_image_spec (object, kw, XBM_LAST, Qxbm)) - return 0; - - xassert (EQ (kw[XBM_TYPE].value, Qxbm)); - - if (kw[XBM_FILE].count) - { - if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count) - return 0; - } - else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value)) - { - /* In-memory XBM file. */ - if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count) - return 0; - } - else - { - Lisp_Object data; - int width, height; - - /* Entries for `:width', `:height' and `:data' must be present. */ - if (!kw[XBM_WIDTH].count - || !kw[XBM_HEIGHT].count - || !kw[XBM_DATA].count) - return 0; - - data = kw[XBM_DATA].value; - width = XFASTINT (kw[XBM_WIDTH].value); - height = XFASTINT (kw[XBM_HEIGHT].value); - - /* Check type of data, and width and height against contents of - data. */ - if (VECTORP (data)) - { - int i; - - /* Number of elements of the vector must be >= height. */ - if (XVECTOR (data)->size < height) - return 0; - - /* Each string or bool-vector in data must be large enough - for one line of the image. */ - for (i = 0; i < height; ++i) - { - Lisp_Object elt = XVECTOR (data)->contents[i]; - - if (STRINGP (elt)) - { - if (SCHARS (elt) - < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR) - return 0; - } - else if (BOOL_VECTOR_P (elt)) - { - if (XBOOL_VECTOR (elt)->size < width) - return 0; - } - else - return 0; - } - } - else if (STRINGP (data)) - { - if (SCHARS (data) - < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height) - return 0; - } - else if (BOOL_VECTOR_P (data)) - { - if (XBOOL_VECTOR (data)->size < width * height) - return 0; - } - else - return 0; - } - - return 1; -} - - -/* Scan a bitmap file. FP is the stream to read from. Value is - either an enumerator from enum xbm_token, or a character for a - single-character token, or 0 at end of file. If scanning an - identifier, store the lexeme of the identifier in SVAL. If - scanning a number, store its value in *IVAL. */ - -static int -xbm_scan (s, end, sval, ival) - char **s, *end; - char *sval; - int *ival; -{ - int c; - - loop: - - /* Skip white space. */ - while (*s < end && (c = *(*s)++, isspace (c))) - ; - - if (*s >= end) - c = 0; - else if (isdigit (c)) - { - int value = 0, digit; - - if (c == '0' && *s < end) - { - c = *(*s)++; - if (c == 'x' || c == 'X') - { - while (*s < end) - { - c = *(*s)++; - if (isdigit (c)) - digit = c - '0'; - else if (c >= 'a' && c <= 'f') - digit = c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - digit = c - 'A' + 10; - else - break; - value = 16 * value + digit; - } - } - else if (isdigit (c)) - { - value = c - '0'; - while (*s < end - && (c = *(*s)++, isdigit (c))) - value = 8 * value + c - '0'; - } - } - else - { - value = c - '0'; - while (*s < end - && (c = *(*s)++, isdigit (c))) - value = 10 * value + c - '0'; - } - - if (*s < end) - *s = *s - 1; - *ival = value; - c = XBM_TK_NUMBER; - } - else if (isalpha (c) || c == '_') - { - *sval++ = c; - while (*s < end - && (c = *(*s)++, (isalnum (c) || c == '_'))) - *sval++ = c; - *sval = 0; - if (*s < end) - *s = *s - 1; - c = XBM_TK_IDENT; - } - else if (c == '/' && **s == '*') - { - /* C-style comment. */ - ++*s; - while (**s && (**s != '*' || *(*s + 1) != '/')) - ++*s; - if (**s) - { - *s += 2; - goto loop; - } - } - - return c; -} - - -/* XBM bits seem to be backward within bytes compared with how - Windows does things. */ -static unsigned char reflect_byte (unsigned char orig) -{ - int i; - unsigned char reflected = 0x00; - for (i = 0; i < 8; i++) - { - if (orig & (0x01 << i)) - reflected |= 0x80 >> i; - } - return reflected; -} - - -/* Create a Windows bitmap from X bitmap data. */ -static HBITMAP -w32_create_pixmap_from_bitmap_data (int width, int height, char *data) -{ - int i, j, w1, w2; - char *bits, *p; - HBITMAP bmp; - - w1 = (width + 7) / 8; /* nb of 8bits elt in X bitmap */ - w2 = ((width + 15) / 16) * 2; /* nb of 16bits elt in W32 bitmap */ - bits = (char *) alloca (height * w2); - bzero (bits, height * w2); - for (i = 0; i < height; i++) - { - p = bits + i*w2; - for (j = 0; j < w1; j++) - *p++ = reflect_byte(*data++); - } - bmp = CreateBitmap (width, height, 1, 1, bits); - - return bmp; -} - - -/* Replacement for XReadBitmapFileData which isn't available under old - X versions. CONTENTS is a pointer to a buffer to parse; END is the - buffer's end. Set *WIDTH and *HEIGHT to the width and height of - the image. Return in *DATA the bitmap data allocated with xmalloc. - Value is non-zero if successful. DATA null means just test if - CONTENTS looks like an in-memory XBM file. */ - -static int -xbm_read_bitmap_data (contents, end, width, height, data) - char *contents, *end; - int *width, *height; - unsigned char **data; -{ - char *s = contents; - char buffer[BUFSIZ]; - int padding_p = 0; - int v10 = 0; - int bytes_per_line, i, nbytes; - unsigned char *p; - int value; - int LA1; - -#define match() \ - LA1 = xbm_scan (&s, end, buffer, &value) - -#define expect(TOKEN) \ - if (LA1 != (TOKEN)) \ - goto failure; \ - else \ - match () - -#define expect_ident(IDENT) \ - if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \ - match (); \ - else \ - goto failure - - *width = *height = -1; - if (data) - *data = NULL; - LA1 = xbm_scan (&s, end, buffer, &value); - - /* Parse defines for width, height and hot-spots. */ - while (LA1 == '#') - { - match (); - expect_ident ("define"); - expect (XBM_TK_IDENT); - - if (LA1 == XBM_TK_NUMBER); - { - char *p = strrchr (buffer, '_'); - p = p ? p + 1 : buffer; - if (strcmp (p, "width") == 0) - *width = value; - else if (strcmp (p, "height") == 0) - *height = value; - } - expect (XBM_TK_NUMBER); - } - - if (*width < 0 || *height < 0) - goto failure; - else if (data == NULL) - goto success; - - /* Parse bits. Must start with `static'. */ - expect_ident ("static"); - if (LA1 == XBM_TK_IDENT) - { - if (strcmp (buffer, "unsigned") == 0) - { - match (); - expect_ident ("char"); - } - else if (strcmp (buffer, "short") == 0) - { - match (); - v10 = 1; - if (*width % 16 && *width % 16 < 9) - padding_p = 1; - } - else if (strcmp (buffer, "char") == 0) - match (); - else - goto failure; - } - else - goto failure; - - expect (XBM_TK_IDENT); - expect ('['); - expect (']'); - expect ('='); - expect ('{'); - - bytes_per_line = (*width + 7) / 8 + padding_p; - nbytes = bytes_per_line * *height; - p = *data = (char *) xmalloc (nbytes); - - if (v10) - { - for (i = 0; i < nbytes; i += 2) - { - int val = value; - expect (XBM_TK_NUMBER); - - *p++ = ~ val; - if (!padding_p || ((i + 2) % bytes_per_line)) - *p++ = ~ (value >> 8); - - if (LA1 == ',' || LA1 == '}') - match (); - else - goto failure; - } - } - else - { - for (i = 0; i < nbytes; ++i) - { - int val = value; - expect (XBM_TK_NUMBER); - - *p++ = ~ val; - - if (LA1 == ',' || LA1 == '}') - match (); - else - goto failure; - } - } - - success: - return 1; - - failure: - - if (data && *data) - { - xfree (*data); - *data = NULL; - } - return 0; - -#undef match -#undef expect -#undef expect_ident -} - -static void convert_mono_to_color_image (f, img, foreground, background) - struct frame *f; - struct image *img; - COLORREF foreground, background; -{ - HDC hdc, old_img_dc, new_img_dc; - HGDIOBJ old_prev, new_prev; - HBITMAP new_pixmap; - - hdc = get_frame_dc (f); - old_img_dc = CreateCompatibleDC (hdc); - new_img_dc = CreateCompatibleDC (hdc); - new_pixmap = CreateCompatibleBitmap (hdc, img->width, img->height); - release_frame_dc (f, hdc); - old_prev = SelectObject (old_img_dc, img->pixmap); - new_prev = SelectObject (new_img_dc, new_pixmap); - SetTextColor (new_img_dc, foreground); - SetBkColor (new_img_dc, background); - - BitBlt (new_img_dc, 0, 0, img->width, img->height, old_img_dc, - 0, 0, SRCCOPY); - - SelectObject (old_img_dc, old_prev); - SelectObject (new_img_dc, new_prev); - DeleteDC (old_img_dc); - DeleteDC (new_img_dc); - DeleteObject (img->pixmap); - if (new_pixmap == 0) - fprintf (stderr, "Failed to convert image to color.\n"); - else - img->pixmap = new_pixmap; -} - -/* Load XBM image IMG which will be displayed on frame F from buffer - CONTENTS. END is the end of the buffer. Value is non-zero if - successful. */ - -static int -xbm_load_image (f, img, contents, end) - struct frame *f; - struct image *img; - char *contents, *end; -{ - int rc; - unsigned char *data; - int success_p = 0; - - rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data); - if (rc) - { - unsigned long foreground = FRAME_FOREGROUND_PIXEL (f); - unsigned long background = FRAME_BACKGROUND_PIXEL (f); - int non_default_colors = 0; - Lisp_Object value; - - xassert (img->width > 0 && img->height > 0); - - /* Get foreground and background colors, maybe allocate colors. */ - value = image_spec_value (img->spec, QCforeground, NULL); - if (!NILP (value)) - { - foreground = x_alloc_image_color (f, img, value, foreground); - non_default_colors = 1; - } - value = image_spec_value (img->spec, QCbackground, NULL); - if (!NILP (value)) - { - background = x_alloc_image_color (f, img, value, background); - img->background = background; - img->background_valid = 1; - non_default_colors = 1; - } - img->pixmap - = w32_create_pixmap_from_bitmap_data (img->width, img->height, data); - - /* If colors were specified, transfer the bitmap to a color one. */ - if (non_default_colors) - convert_mono_to_color_image (f, img, foreground, background); - - xfree (data); - - if (img->pixmap == 0) - { - x_clear_image (f, img); - image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil); - } - else - success_p = 1; - } - else - image_error ("Error loading XBM image `%s'", img->spec, Qnil); - - return success_p; -} - - -/* Value is non-zero if DATA looks like an in-memory XBM file. */ - -static int -xbm_file_p (data) - Lisp_Object data; -{ - int w, h; - return (STRINGP (data) - && xbm_read_bitmap_data (SDATA (data), - (SDATA (data) - + SBYTES (data)), - &w, &h, NULL)); -} - - -/* Fill image IMG which is used on frame F with pixmap data. Value is - non-zero if successful. */ - -static int -xbm_load (f, img) - struct frame *f; - struct image *img; -{ - int success_p = 0; - Lisp_Object file_name; - - xassert (xbm_image_p (img->spec)); - - /* If IMG->spec specifies a file name, create a non-file spec from it. */ - file_name = image_spec_value (img->spec, QCfile, NULL); - if (STRINGP (file_name)) - { - Lisp_Object file; - char *contents; - int size; - struct gcpro gcpro1; - - file = x_find_image_file (file_name); - GCPRO1 (file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", file_name, Qnil); - UNGCPRO; - return 0; - } - - contents = slurp_file (SDATA (file), &size); - if (contents == NULL) - { - image_error ("Error loading XBM image `%s'", img->spec, Qnil); - UNGCPRO; - return 0; - } - - success_p = xbm_load_image (f, img, contents, contents + size); - UNGCPRO; - } - else - { - struct image_keyword fmt[XBM_LAST]; - Lisp_Object data; - unsigned long foreground = FRAME_FOREGROUND_PIXEL (f); - unsigned long background = FRAME_BACKGROUND_PIXEL (f); - int non_default_colors = 0; - char *bits; - int parsed_p; - int in_memory_file_p = 0; - - /* See if data looks like an in-memory XBM file. */ - data = image_spec_value (img->spec, QCdata, NULL); - in_memory_file_p = xbm_file_p (data); - - /* Parse the image specification. */ - bcopy (xbm_format, fmt, sizeof fmt); - parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm); - xassert (parsed_p); - - /* Get specified width, and height. */ - if (!in_memory_file_p) - { - img->width = XFASTINT (fmt[XBM_WIDTH].value); - img->height = XFASTINT (fmt[XBM_HEIGHT].value); - xassert (img->width > 0 && img->height > 0); - } - - /* Get foreground and background colors, maybe allocate colors. */ - if (fmt[XBM_FOREGROUND].count - && STRINGP (fmt[XBM_FOREGROUND].value)) - { - foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value, - foreground); - non_default_colors = 1; - } - - if (fmt[XBM_BACKGROUND].count - && STRINGP (fmt[XBM_BACKGROUND].value)) - { - background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value, - background); - non_default_colors = 1; - } - - if (in_memory_file_p) - success_p = xbm_load_image (f, img, SDATA (data), - (SDATA (data) - + SBYTES (data))); - else - { - if (VECTORP (data)) - { - int i; - char *p; - int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR; - - p = bits = (char *) alloca (nbytes * img->height); - for (i = 0; i < img->height; ++i, p += nbytes) - { - Lisp_Object line = XVECTOR (data)->contents[i]; - if (STRINGP (line)) - bcopy (SDATA (line), p, nbytes); - else - bcopy (XBOOL_VECTOR (line)->data, p, nbytes); - } - } - else if (STRINGP (data)) - bits = SDATA (data); - else - bits = XBOOL_VECTOR (data)->data; - - /* Create the pixmap. */ - img->pixmap - = w32_create_pixmap_from_bitmap_data (img->width, img->height, - bits); - - /* If colors were specified, transfer the bitmap to a color one. */ - if (non_default_colors) - convert_mono_to_color_image (f, img, foreground, background); - - if (img->pixmap) - success_p = 1; - else - { - image_error ("Unable to create pixmap for XBM image `%s'", - img->spec, Qnil); - x_clear_image (f, img); - } - } - } - - return success_p; -} - - - -/*********************************************************************** - XPM images - ***********************************************************************/ - -#if HAVE_XPM - -static int xpm_image_p P_ ((Lisp_Object object)); -static int xpm_load P_ ((struct frame *f, struct image *img)); -static int xpm_valid_color_symbols_p P_ ((Lisp_Object)); - -/* Indicate to xpm.h that we don't have Xlib. */ -#define FOR_MSW -/* simx.h in xpm defines XColor and XImage differently than Emacs. */ -#define XColor xpm_XColor -#define XImage xpm_XImage -#define PIXEL_ALREADY_TYPEDEFED -#include "X11/xpm.h" -#undef FOR_MSW -#undef XColor -#undef XImage -#undef PIXEL_ALREADY_TYPEDEFED - -/* The symbol `xpm' identifying XPM-format images. */ - -Lisp_Object Qxpm; - -/* Indices of image specification fields in xpm_format, below. */ - -enum xpm_keyword_index -{ - XPM_TYPE, - XPM_FILE, - XPM_DATA, - XPM_ASCENT, - XPM_MARGIN, - XPM_RELIEF, - XPM_ALGORITHM, - XPM_HEURISTIC_MASK, - XPM_MASK, - XPM_COLOR_SYMBOLS, - XPM_BACKGROUND, - XPM_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid XPM image specifications. */ - -static struct image_keyword xpm_format[XPM_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":file", IMAGE_STRING_VALUE, 0}, - {":data", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 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}, - {":background", IMAGE_STRING_OR_NIL_VALUE, 0} -}; - -/* Structure describing the image type XPM. */ - -static struct image_type xpm_type = -{ - &Qxpm, - xpm_image_p, - xpm_load, - x_clear_image, - NULL -}; - - -/* XPM library details. */ - -DEF_IMGLIB_FN (XpmFreeAttributes); -DEF_IMGLIB_FN (XpmCreateImageFromBuffer); -DEF_IMGLIB_FN (XpmReadFileToImage); -DEF_IMGLIB_FN (XImageFree); - - -static int -init_xpm_functions (library) - HMODULE library; -{ - LOAD_IMGLIB_FN (library, XpmFreeAttributes); - LOAD_IMGLIB_FN (library, XpmCreateImageFromBuffer); - LOAD_IMGLIB_FN (library, XpmReadFileToImage); - LOAD_IMGLIB_FN (library, XImageFree); - - return 1; -} - -/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list - for XPM images. Such a list must consist of conses whose car and - cdr are strings. */ - -static int -xpm_valid_color_symbols_p (color_symbols) - Lisp_Object color_symbols; -{ - while (CONSP (color_symbols)) - { - Lisp_Object sym = XCAR (color_symbols); - if (!CONSP (sym) - || !STRINGP (XCAR (sym)) - || !STRINGP (XCDR (sym))) - break; - color_symbols = XCDR (color_symbols); - } - - return NILP (color_symbols); -} - - -/* Value is non-zero if OBJECT is a valid XPM image specification. */ - -static int -xpm_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[XPM_LAST]; - bcopy (xpm_format, fmt, sizeof fmt); - return (parse_image_spec (object, fmt, XPM_LAST, Qxpm) - /* Either `:file' or `:data' must be present. */ - && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1 - /* Either no `:color-symbols' or it's a list of conses - whose car and cdr are strings. */ - && (fmt[XPM_COLOR_SYMBOLS].count == 0 - || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))); -} - - -/* Load image IMG which will be displayed on frame F. Value is - non-zero if successful. */ - -static int -xpm_load (f, img) - struct frame *f; - struct image *img; -{ - HDC hdc; - int rc; - XpmAttributes attrs; - Lisp_Object specified_file, color_symbols; - xpm_XImage * xpm_image, * xpm_mask; - - /* Configure the XPM lib. Use the visual of frame F. Allocate - close colors. Return colors allocated. */ - bzero (&attrs, sizeof attrs); - xpm_image = xpm_mask = NULL; - -#if 0 - attrs.visual = FRAME_X_VISUAL (f); - attrs.colormap = FRAME_X_COLORMAP (f); - attrs.valuemask |= XpmVisual; - attrs.valuemask |= XpmColormap; -#endif - attrs.valuemask |= XpmReturnAllocPixels; -#ifdef XpmAllocCloseColors - attrs.alloc_close_colors = 1; - attrs.valuemask |= XpmAllocCloseColors; -#else - attrs.closeness = 600; - attrs.valuemask |= XpmCloseness; -#endif - - /* If image specification contains symbolic color definitions, add - these to `attrs'. */ - color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL); - if (CONSP (color_symbols)) - { - Lisp_Object tail; - XpmColorSymbol *xpm_syms; - int i, size; - - attrs.valuemask |= XpmColorSymbols; - - /* Count number of symbols. */ - attrs.numsymbols = 0; - for (tail = color_symbols; CONSP (tail); tail = XCDR (tail)) - ++attrs.numsymbols; - - /* Allocate an XpmColorSymbol array. */ - size = attrs.numsymbols * sizeof *xpm_syms; - xpm_syms = (XpmColorSymbol *) alloca (size); - bzero (xpm_syms, size); - attrs.colorsymbols = xpm_syms; - - /* Fill the color symbol array. */ - for (tail = color_symbols, i = 0; - CONSP (tail); - ++i, tail = XCDR (tail)) - { - Lisp_Object name = XCAR (XCAR (tail)); - Lisp_Object color = XCDR (XCAR (tail)); - xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1); - strcpy (xpm_syms[i].name, SDATA (name)); - xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1); - strcpy (xpm_syms[i].value, SDATA (color)); - } - } - - /* Create a pixmap for the image, either from a file, or from a - string buffer containing data in the same format as an XPM file. */ - - specified_file = image_spec_value (img->spec, QCfile, NULL); - - { - HDC frame_dc = get_frame_dc (f); - hdc = CreateCompatibleDC (frame_dc); - release_frame_dc (f, frame_dc); - } - - if (STRINGP (specified_file)) - { - Lisp_Object file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - return 0; - } - - /* XpmReadFileToPixmap is not available in the Windows port of - libxpm. But XpmReadFileToImage almost does what we want. */ - rc = fn_XpmReadFileToImage (&hdc, SDATA (file), - &xpm_image, &xpm_mask, - &attrs); - } - else - { - Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL); - /* XpmCreatePixmapFromBuffer is not available in the Windows port - of libxpm. But XpmCreateImageFromBuffer almost does what we want. */ - rc = fn_XpmCreateImageFromBuffer (&hdc, SDATA (buffer), - &xpm_image, &xpm_mask, - &attrs); - } - - if (rc == XpmSuccess) - { - int i; - - /* W32 XPM uses XImage to wrap what W32 Emacs calls a Pixmap, - plus some duplicate attributes. */ - if (xpm_image && xpm_image->bitmap) - { - img->pixmap = xpm_image->bitmap; - /* XImageFree in libXpm frees XImage struct without destroying - the bitmap, which is what we want. */ - fn_XImageFree (xpm_image); - } - if (xpm_mask && xpm_mask->bitmap) - { - /* The mask appears to be inverted compared with what we expect. - TODO: invert our expectations. See other places where we - have to invert bits because our idea of masks is backwards. */ - HGDIOBJ old_obj; - old_obj = SelectObject (hdc, xpm_mask->bitmap); - - PatBlt (hdc, 0, 0, xpm_mask->width, xpm_mask->height, DSTINVERT); - SelectObject (hdc, old_obj); - - img->mask = xpm_mask->bitmap; - fn_XImageFree (xpm_mask); - DeleteDC (hdc); - } - - DeleteDC (hdc); - - /* Remember allocated colors. */ - img->ncolors = attrs.nalloc_pixels; - img->colors = (unsigned long *) xmalloc (img->ncolors - * sizeof *img->colors); - for (i = 0; i < attrs.nalloc_pixels; ++i) - img->colors[i] = attrs.alloc_pixels[i]; - - img->width = attrs.width; - img->height = attrs.height; - xassert (img->width > 0 && img->height > 0); - - /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */ - fn_XpmFreeAttributes (&attrs); - } - else - { - DeleteDC (hdc); - - switch (rc) - { - case XpmOpenFailed: - image_error ("Error opening XPM file (%s)", img->spec, Qnil); - break; - - case XpmFileInvalid: - image_error ("Invalid XPM file (%s)", img->spec, Qnil); - break; - - case XpmNoMemory: - image_error ("Out of memory (%s)", img->spec, Qnil); - break; - - case XpmColorFailed: - image_error ("Color allocation error (%s)", img->spec, Qnil); - break; - - default: - image_error ("Unknown error (%s)", img->spec, Qnil); - break; - } - } - - return rc == XpmSuccess; -} - -#endif /* HAVE_XPM != 0 */ - - -#if 0 /* TODO : Color tables on W32. */ -/*********************************************************************** - Color table - ***********************************************************************/ - -/* An entry in the color table mapping an RGB color to a pixel color. */ - -struct ct_color -{ - int r, g, b; - unsigned long pixel; - - /* Next in color table collision list. */ - struct ct_color *next; -}; - -/* The bucket vector size to use. Must be prime. */ - -#define CT_SIZE 101 - -/* Value is a hash of the RGB color given by R, G, and B. */ - -#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B)) - -/* The color hash table. */ - -struct ct_color **ct_table; - -/* Number of entries in the color table. */ - -int ct_colors_allocated; - -/* Function prototypes. */ - -static void init_color_table P_ ((void)); -static void free_color_table P_ ((void)); -static unsigned long *colors_in_color_table P_ ((int *n)); -static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b)); -static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p)); - - -/* Initialize the color table. */ - -static void -init_color_table () -{ - int size = CT_SIZE * sizeof (*ct_table); - ct_table = (struct ct_color **) xmalloc (size); - bzero (ct_table, size); - ct_colors_allocated = 0; -} - - -/* Free memory associated with the color table. */ - -static void -free_color_table () -{ - int i; - struct ct_color *p, *next; - - for (i = 0; i < CT_SIZE; ++i) - for (p = ct_table[i]; p; p = next) - { - next = p->next; - xfree (p); - } - - xfree (ct_table); - ct_table = NULL; -} - - -/* Value is a pixel color for RGB color R, G, B on frame F. If an - entry for that color already is in the color table, return the - pixel color of that entry. Otherwise, allocate a new color for R, - G, B, and make an entry in the color table. */ - -static unsigned long -lookup_rgb_color (f, r, g, b) - struct frame *f; - int r, g, b; -{ - unsigned hash = CT_HASH_RGB (r, g, b); - int i = hash % CT_SIZE; - struct ct_color *p; - - for (p = ct_table[i]; p; p = p->next) - if (p->r == r && p->g == g && p->b == b) - break; - - if (p == NULL) - { - COLORREF color; - Colormap cmap; - int rc; - - color = PALETTERGB (r, g, b); - - ++ct_colors_allocated; - - p = (struct ct_color *) xmalloc (sizeof *p); - p->r = r; - p->g = g; - p->b = b; - p->pixel = color; - p->next = ct_table[i]; - ct_table[i] = p; - } - - return p->pixel; -} - - -/* Look up pixel color PIXEL which is used on frame F in the color - table. If not already present, allocate it. Value is PIXEL. */ - -static unsigned long -lookup_pixel_color (f, pixel) - struct frame *f; - unsigned long pixel; -{ - int i = pixel % CT_SIZE; - struct ct_color *p; - - for (p = ct_table[i]; p; p = p->next) - if (p->pixel == pixel) - break; - - if (p == NULL) - { - XColor color; - Colormap cmap; - int rc; - - BLOCK_INPUT; - - cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); - color.pixel = pixel; - XQueryColor (NULL, cmap, &color); - rc = x_alloc_nearest_color (f, cmap, &color); - UNBLOCK_INPUT; - - if (rc) - { - ++ct_colors_allocated; - - p = (struct ct_color *) xmalloc (sizeof *p); - p->r = color.red; - p->g = color.green; - p->b = color.blue; - p->pixel = pixel; - p->next = ct_table[i]; - ct_table[i] = p; - } - else - return FRAME_FOREGROUND_PIXEL (f); - } - return p->pixel; -} - - -/* Value is a vector of all pixel colors contained in the color table, - allocated via xmalloc. Set *N to the number of colors. */ - -static unsigned long * -colors_in_color_table (n) - int *n; -{ - int i, j; - struct ct_color *p; - unsigned long *colors; - - if (ct_colors_allocated == 0) - { - *n = 0; - colors = NULL; - } - else - { - colors = (unsigned long *) xmalloc (ct_colors_allocated - * sizeof *colors); - *n = ct_colors_allocated; - - for (i = j = 0; i < CT_SIZE; ++i) - for (p = ct_table[i]; p; p = p->next) - colors[j++] = p->pixel; - } - - return colors; -} - -#endif /* TODO */ - - -/*********************************************************************** - Algorithms - ***********************************************************************/ -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)); -static void XPutPixel (XImage *, int, int, COLORREF); - -/* Non-zero means draw a cross on images having `:conversion - disabled'. */ - -int cross_disabled_images; - -/* Edge detection matrices for different edge-detection - strategies. */ - -static int emboss_matrix[9] = { - /* x - 1 x x + 1 */ - 2, -1, 0, /* y - 1 */ - -1, 0, 1, /* y */ - 0, 1, -2 /* y + 1 */ -}; - -static int laplace_matrix[9] = { - /* x - 1 x x + 1 */ - 1, 0, 0, /* y - 1 */ - 0, 0, 0, /* y */ - 0, 0, -1 /* y + 1 */ -}; - -/* Value is the intensity of the color whose red/green/blue values - are R, G, and B. */ - -#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6) - - -/* On frame F, return an array of XColor structures describing image - IMG->pixmap. Each XColor structure has its pixel color set. RGB_P - non-zero means also fill the red/green/blue members of the XColor - structures. Value is a pointer to the array of XColors structures, - allocated with xmalloc; it must be freed by the caller. */ - -static XColor * -x_to_xcolors (f, img, rgb_p) - struct frame *f; - struct image *img; - int rgb_p; -{ - int x, y; - XColor *colors, *p; - HDC hdc, bmpdc; - HGDIOBJ prev; - - colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors); - - /* Load the image into a memory device context. */ - hdc = get_frame_dc (f); - bmpdc = CreateCompatibleDC (hdc); - release_frame_dc (f, hdc); - prev = SelectObject (bmpdc, img->pixmap); - - /* Fill the `pixel' members of the XColor array. I wished there - were an easy and portable way to circumvent XGetPixel. */ - p = colors; - for (y = 0; y < img->height; ++y) - { - XColor *row = p; - - for (x = 0; x < img->width; ++x, ++p) - { - /* TODO: palette support needed here? */ - p->pixel = GetPixel (bmpdc, x, y); - - if (rgb_p) - { - p->red = 256 * GetRValue (p->pixel); - p->green = 256 * GetGValue (p->pixel); - p->blue = 256 * GetBValue (p->pixel); - } - } - } - - SelectObject (bmpdc, prev); - DeleteDC (bmpdc); - - return colors; -} - -/* Put a pixel of COLOR at position X, Y in XIMG. XIMG must have been - created with CreateDIBSection, with the pointer to the bit values - stored in ximg->data. */ - -static void XPutPixel (ximg, x, y, color) - XImage * ximg; - int x, y; - COLORREF color; -{ - int width = ximg->info.bmiHeader.biWidth; - int height = ximg->info.bmiHeader.biHeight; - unsigned char * pixel; - - /* True color images. */ - if (ximg->info.bmiHeader.biBitCount == 24) - { - int rowbytes = width * 3; - /* Ensure scanlines are aligned on 4 byte boundaries. */ - if (rowbytes % 4) - rowbytes += 4 - (rowbytes % 4); - - pixel = ximg->data + y * rowbytes + x * 3; - /* Windows bitmaps are in BGR order. */ - *pixel = GetBValue (color); - *(pixel + 1) = GetGValue (color); - *(pixel + 2) = GetRValue (color); - } - /* Monochrome images. */ - else if (ximg->info.bmiHeader.biBitCount == 1) - { - int rowbytes = width / 8; - /* Ensure scanlines are aligned on 4 byte boundaries. */ - if (rowbytes % 4) - rowbytes += 4 - (rowbytes % 4); - pixel = ximg->data + y * rowbytes + x / 8; - /* Filter out palette info. */ - if (color & 0x00ffffff) - *pixel = *pixel | (1 << x % 8); - else - *pixel = *pixel & ~(1 << x % 8); - } - else - image_error ("XPutPixel: palette image not supported.", Qnil, Qnil); -} - -/* Create IMG->pixmap from an array COLORS of XColor structures, whose - RGB members are set. F is the frame on which this all happens. - COLORS will be freed; an existing IMG->pixmap will be freed, too. */ - -static void -x_from_xcolors (f, img, colors) - struct frame *f; - struct image *img; - XColor *colors; -{ - int x, y; - XImage *oimg; - Pixmap pixmap; - XColor *p; -#if 0 /* TODO: color tables. */ - init_color_table (); -#endif - x_create_x_image_and_pixmap (f, img->width, img->height, 0, - &oimg, &pixmap); - p = colors; - for (y = 0; y < img->height; ++y) - for (x = 0; x < img->width; ++x, ++p) - { - unsigned long pixel; -#if 0 /* TODO: color tables. */ - pixel = lookup_rgb_color (f, p->red, p->green, p->blue); -#else - pixel = PALETTERGB (p->red / 256, p->green / 256, p->blue / 256); -#endif - XPutPixel (oimg, x, y, pixel); - } - - xfree (colors); - x_clear_image_1 (f, img, 1, 0, 1); - - x_put_x_image (f, oimg, pixmap, img->width, img->height); - x_destroy_x_image (oimg); - img->pixmap = pixmap; -#if 0 /* TODO: color tables. */ - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); -#endif -} - - -/* On frame F, perform edge-detection on image IMG. - - MATRIX is a nine-element array specifying the transformation - matrix. See emboss_matrix for an example. - - COLOR_ADJUST is a color adjustment added to each pixel of the - outgoing image. */ - -static void -x_detect_edges (f, img, matrix, color_adjust) - struct frame *f; - struct image *img; - int matrix[9], color_adjust; -{ - XColor *colors = x_to_xcolors (f, img, 1); - XColor *new, *p; - int x, y, i, sum; - - for (i = sum = 0; i < 9; ++i) - sum += abs (matrix[i]); - -#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X)) - - new = (XColor *) xmalloc (img->width * img->height * sizeof *new); - - for (y = 0; y < img->height; ++y) - { - p = COLOR (new, 0, y); - p->red = p->green = p->blue = 0xffff/2; - p = COLOR (new, img->width - 1, y); - p->red = p->green = p->blue = 0xffff/2; - } - - for (x = 1; x < img->width - 1; ++x) - { - p = COLOR (new, x, 0); - p->red = p->green = p->blue = 0xffff/2; - p = COLOR (new, x, img->height - 1); - p->red = p->green = p->blue = 0xffff/2; - } - - for (y = 1; y < img->height - 1; ++y) - { - p = COLOR (new, 1, y); - - for (x = 1; x < img->width - 1; ++x, ++p) - { - int r, g, b, y1, x1; - - r = g = b = i = 0; - for (y1 = y - 1; y1 < y + 2; ++y1) - for (x1 = x - 1; x1 < x + 2; ++x1, ++i) - if (matrix[i]) - { - XColor *t = COLOR (colors, x1, y1); - r += matrix[i] * t->red; - g += matrix[i] * t->green; - b += matrix[i] * t->blue; - } - - r = (r / sum + color_adjust) & 0xffff; - g = (g / sum + color_adjust) & 0xffff; - b = (b / sum + color_adjust) & 0xffff; - p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b); - } - } - - xfree (colors); - x_from_xcolors (f, img, new); - -#undef COLOR -} - - -/* Perform the pre-defined `emboss' edge-detection on image IMG - on frame F. */ - -static void -x_emboss (f, img) - struct frame *f; - struct image *img; -{ - x_detect_edges (f, img, emboss_matrix, 0xffff / 2); -} - - -/* Transform image IMG which is used on frame F with a Laplace - edge-detection algorithm. The result is an image that can be used - to draw disabled buttons, for example. */ - -static void -x_laplace (f, img) - struct frame *f; - struct image *img; -{ - x_detect_edges (f, img, laplace_matrix, 45000); -} - - -/* Perform edge-detection on image IMG on frame F, with specified - transformation matrix MATRIX and color-adjustment COLOR_ADJUST. - - MATRIX must be either - - - a list of at least 9 numbers in row-major form - - a vector of at least 9 numbers - - COLOR_ADJUST nil means use a default; otherwise it must be a - number. */ - -static void -x_edge_detection (f, img, matrix, color_adjust) - struct frame *f; - struct image *img; - Lisp_Object matrix, color_adjust; -{ - int i = 0; - int trans[9]; - - if (CONSP (matrix)) - { - for (i = 0; - i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix)); - ++i, matrix = XCDR (matrix)) - trans[i] = XFLOATINT (XCAR (matrix)); - } - else if (VECTORP (matrix) && ASIZE (matrix) >= 9) - { - for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i) - trans[i] = XFLOATINT (AREF (matrix, i)); - } - - if (NILP (color_adjust)) - color_adjust = make_number (0xffff / 2); - - if (i == 9 && NUMBERP (color_adjust)) - x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust)); -} - - -/* Transform image IMG on frame F so that it looks disabled. */ - -static void -x_disable_image (f, img) - struct frame *f; - struct image *img; -{ - struct w32_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); - - if (dpyinfo->n_planes * dpyinfo->n_cbits >= 2) - { - /* Color (or grayscale). Convert to gray, and equalize. Just - drawing such images with a stipple can look very odd, so - we're using this method instead. */ - XColor *colors = x_to_xcolors (f, img, 1); - XColor *p, *end; - const int h = 15000; - const int l = 30000; - - for (p = colors, end = colors + img->width * img->height; - p < end; - ++p) - { - int i = COLOR_INTENSITY (p->red, p->green, p->blue); - int i2 = (0xffff - h - l) * i / 0xffff + l; - p->red = p->green = p->blue = i2; - } - - x_from_xcolors (f, img, colors); - } - - /* Draw a cross over the disabled image, if we must or if we - should. */ - if (dpyinfo->n_planes * dpyinfo->n_cbits < 2 || cross_disabled_images) - { - HDC hdc, bmpdc; - HGDIOBJ prev; - - hdc = get_frame_dc (f); - bmpdc = CreateCompatibleDC (hdc); - release_frame_dc (f, hdc); - - prev = SelectObject (bmpdc, img->pixmap); - - SetTextColor (bmpdc, BLACK_PIX_DEFAULT (f)); - MoveToEx (bmpdc, 0, 0, NULL); - LineTo (bmpdc, img->width - 1, img->height - 1); - MoveToEx (bmpdc, 0, img->height - 1, NULL); - LineTo (bmpdc, img->width - 1, 0); - - if (img->mask) - { - SelectObject (bmpdc, img->mask); - SetTextColor (bmpdc, WHITE_PIX_DEFAULT (f)); - MoveToEx (bmpdc, 0, 0, NULL); - LineTo (bmpdc, img->width - 1, img->height - 1); - MoveToEx (bmpdc, 0, img->height - 1, NULL); - LineTo (bmpdc, img->width - 1, 0); - } - SelectObject (bmpdc, prev); - DeleteDC (bmpdc); - } -} - - -/* Build a mask for image IMG which is used on frame F. FILE is the - name of an image file, for error messages. HOW determines how to - determine the background color of IMG. If it is a list '(R G B)', - with R, G, and B being integers >= 0, take that as the color of the - background. Otherwise, determine the background color of IMG - heuristically. Value is non-zero if successful. */ - -static int -x_build_heuristic_mask (f, img, how) - struct frame *f; - struct image *img; - Lisp_Object how; -{ - HDC img_dc, frame_dc; - HGDIOBJ prev; - char *mask_img; - int x, y, rc, use_img_background; - unsigned long bg = 0; - int row_width; - - if (img->mask) - { - DeleteObject (img->mask); - img->mask = NULL; - img->background_transparent_valid = 0; - } - - /* Create the bit array serving as mask. */ - row_width = (img->width + 7) / 8; - mask_img = xmalloc (row_width * img->height); - bzero (mask_img, row_width * img->height); - - /* Create a memory device context for IMG->pixmap. */ - frame_dc = get_frame_dc (f); - img_dc = CreateCompatibleDC (frame_dc); - release_frame_dc (f, frame_dc); - prev = SelectObject (img_dc, img->pixmap); - - /* Determine the background color of img_dc. If HOW is `(R G B)' - take that as color. Otherwise, use the image's background color. */ - use_img_background = 1; - - if (CONSP (how)) - { - int rgb[3], i; - - for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i) - { - rgb[i] = XFASTINT (XCAR (how)) & 0xffff; - how = XCDR (how); - } - - if (i == 3 && NILP (how)) - { - char color_name[30]; - sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]); - bg = x_alloc_image_color (f, img, build_string (color_name), 0) - & 0x00ffffff; /* Filter out palette info. */ - use_img_background = 0; - } - } - - if (use_img_background) - bg = four_corners_best (img_dc, img->width, img->height); - - /* Set all bits in mask_img to 1 whose color in ximg is different - from the background color bg. */ - for (y = 0; y < img->height; ++y) - for (x = 0; x < img->width; ++x) - { - COLORREF p = GetPixel (img_dc, x, y); - if (p != bg) - mask_img[y * row_width + x / 8] |= 1 << (x % 8); - } - - /* Create the mask image. */ - img->mask = w32_create_pixmap_from_bitmap_data (img->width, img->height, - mask_img); - - /* Fill in the background_transparent field while we have the mask handy. */ - SelectObject (img_dc, img->mask); - - image_background_transparent (img, f, img_dc); - - /* Put mask_img into img->mask. */ - x_destroy_x_image ((XImage *)mask_img); - SelectObject (img_dc, prev); - DeleteDC (img_dc); - - return 1; -} - - -/*********************************************************************** - PBM (mono, gray, color) - ***********************************************************************/ - -static int pbm_image_p P_ ((Lisp_Object object)); -static int pbm_load P_ ((struct frame *f, struct image *img)); -static int pbm_scan_number P_ ((unsigned char **, unsigned char *)); - -/* The symbol `pbm' identifying images of this type. */ - -Lisp_Object Qpbm; - -/* Indices of image specification fields in gs_format, below. */ - -enum pbm_keyword_index -{ - PBM_TYPE, - PBM_FILE, - PBM_DATA, - PBM_ASCENT, - PBM_MARGIN, - PBM_RELIEF, - PBM_ALGORITHM, - PBM_HEURISTIC_MASK, - PBM_MASK, - PBM_FOREGROUND, - PBM_BACKGROUND, - PBM_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid user-defined image specifications. */ - -static struct image_keyword pbm_format[PBM_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":file", IMAGE_STRING_VALUE, 0}, - {":data", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 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_OR_NIL_VALUE, 0}, - {":background", IMAGE_STRING_OR_NIL_VALUE, 0} -}; - -/* Structure describing the image type `pbm'. */ - -static struct image_type pbm_type = -{ - &Qpbm, - pbm_image_p, - pbm_load, - x_clear_image, - NULL -}; - - -/* Return non-zero if OBJECT is a valid PBM image specification. */ - -static int -pbm_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[PBM_LAST]; - - bcopy (pbm_format, fmt, sizeof fmt); - - if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)) - return 0; - - /* Must specify either :data or :file. */ - return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1; -} - - -/* Scan a decimal number from *S and return it. Advance *S while - reading the number. END is the end of the string. Value is -1 at - end of input. */ - -static int -pbm_scan_number (s, end) - unsigned char **s, *end; -{ - int c, val = -1; - - while (*s < end) - { - /* Skip white-space. */ - while (*s < end && (c = *(*s)++, isspace (c))) - ; - - if (c == '#') - { - /* Skip comment to end of line. */ - while (*s < end && (c = *(*s)++, c != '\n')) - ; - } - else if (isdigit (c)) - { - /* Read decimal number. */ - val = c - '0'; - while (*s < end && (c = *(*s)++, isdigit (c))) - val = 10 * val + c - '0'; - break; - } - else - break; - } - - return val; -} - - -/* Read FILE into memory. Value is a pointer to a buffer allocated - with xmalloc holding FILE's contents. Value is null if an error - occurred. *SIZE is set to the size of the file. */ - -static char * -pbm_read_file (file, size) - Lisp_Object file; - int *size; -{ - FILE *fp = NULL; - char *buf = NULL; - struct stat st; - - if (stat (SDATA (file), &st) == 0 - && (fp = fopen (SDATA (file), "rb")) != NULL - && (buf = (char *) xmalloc (st.st_size), - fread (buf, 1, st.st_size, fp) == st.st_size)) - { - *size = st.st_size; - fclose (fp); - } - else - { - if (fp) - fclose (fp); - if (buf) - { - xfree (buf); - buf = NULL; - } - } - - return buf; -} - - -/* Load PBM image IMG for use on frame F. */ - -static int -pbm_load (f, img) - struct frame *f; - struct image *img; -{ - int raw_p, x, y; - int width, height, max_color_idx = 0; - XImage *ximg; - Lisp_Object file, specified_file; - enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type; - struct gcpro gcpro1; - unsigned char *contents = NULL; - unsigned char *end, *p; - int size; - - specified_file = image_spec_value (img->spec, QCfile, NULL); - file = Qnil; - GCPRO1 (file); - - if (STRINGP (specified_file)) - { - file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNGCPRO; - return 0; - } - - contents = slurp_file (SDATA (file), &size); - if (contents == NULL) - { - image_error ("Error reading `%s'", file, Qnil); - UNGCPRO; - return 0; - } - - p = contents; - end = contents + size; - } - else - { - Lisp_Object data; - data = image_spec_value (img->spec, QCdata, NULL); - p = SDATA (data); - end = p + SBYTES (data); - } - - /* Check magic number. */ - if (end - p < 2 || *p++ != 'P') - { - image_error ("Not a PBM image: `%s'", img->spec, Qnil); - error: - xfree (contents); - UNGCPRO; - return 0; - } - - switch (*p++) - { - case '1': - raw_p = 0, type = PBM_MONO; - break; - - case '2': - raw_p = 0, type = PBM_GRAY; - break; - - case '3': - raw_p = 0, type = PBM_COLOR; - break; - - case '4': - raw_p = 1, type = PBM_MONO; - break; - - case '5': - raw_p = 1, type = PBM_GRAY; - break; - - case '6': - raw_p = 1, type = PBM_COLOR; - break; - - default: - image_error ("Not a PBM image: `%s'", img->spec, Qnil); - goto error; - } - - /* Read width, height, maximum color-component. Characters - starting with `#' up to the end of a line are ignored. */ - width = pbm_scan_number (&p, end); - height = pbm_scan_number (&p, end); - - if (type != PBM_MONO) - { - max_color_idx = pbm_scan_number (&p, end); - if (raw_p && max_color_idx > 255) - max_color_idx = 255; - } - - if (width < 0 - || height < 0 - || (type != PBM_MONO && max_color_idx < 0)) - goto error; - - if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) - goto error; - -#if 0 /* TODO: color tables. */ - /* Initialize the color hash table. */ - init_color_table (); -#endif - - 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 - && STRINGP (fmt[PBM_FOREGROUND].value)) - fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg); - if (fmt[PBM_BACKGROUND].count - && STRINGP (fmt[PBM_BACKGROUND].value)) - { - bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg); - img->background = bg; - img->background_valid = 1; - } - - for (y = 0; y < height; ++y) - for (x = 0; x < width; ++x) - { - if (raw_p) - { - if ((x & 7) == 0) - c = *p++; - g = c & 0x80; - c <<= 1; - } - else - g = pbm_scan_number (&p, end); - - XPutPixel (ximg, x, y, g ? fg : bg); - } - } - else - { - for (y = 0; y < height; ++y) - for (x = 0; x < width; ++x) - { - int r, g, b; - - if (type == PBM_GRAY) - r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end); - else if (raw_p) - { - r = *p++; - g = *p++; - b = *p++; - } - else - { - r = pbm_scan_number (&p, end); - g = pbm_scan_number (&p, end); - b = pbm_scan_number (&p, end); - } - - if (r < 0 || g < 0 || b < 0) - { - x_destroy_x_image (ximg); - image_error ("Invalid pixel value in image `%s'", - img->spec, Qnil); - goto error; - } - - /* RGB values are now in the range 0..max_color_idx. - Scale this to the range 0..0xff supported by W32. */ - r = (int) ((double) r * 255 / max_color_idx); - g = (int) ((double) g * 255 / max_color_idx); - b = (int) ((double) b * 255 / max_color_idx); - XPutPixel (ximg, x, y, -#if 0 /* TODO: color tables. */ - lookup_rgb_color (f, r, g, b)); -#else - PALETTERGB (r, g, b)); -#endif - } - } - -#if 0 /* TODO: color tables. */ - /* Store in IMG->colors the colors allocated for the image, and - free the color table. */ - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); -#endif - /* Maybe fill in the background field while we have ximg handy. */ - if (NILP (image_spec_value (img->spec, QCbackground, NULL))) - IMAGE_BACKGROUND (img, f, ximg); - - /* Put the image into a pixmap. */ - x_put_x_image (f, ximg, img->pixmap, width, height); - x_destroy_x_image (ximg); - - img->width = width; - img->height = height; - - UNGCPRO; - xfree (contents); - return 1; -} - - -/*********************************************************************** - PNG - ***********************************************************************/ - -#if HAVE_PNG - -#include <png.h> - -/* Function prototypes. */ - -static int png_image_p P_ ((Lisp_Object object)); -static int png_load P_ ((struct frame *f, struct image *img)); - -/* The symbol `png' identifying images of this type. */ - -Lisp_Object Qpng; - -/* Indices of image specification fields in png_format, below. */ - -enum png_keyword_index -{ - PNG_TYPE, - PNG_DATA, - PNG_FILE, - PNG_ASCENT, - PNG_MARGIN, - PNG_RELIEF, - PNG_ALGORITHM, - PNG_HEURISTIC_MASK, - PNG_MASK, - PNG_BACKGROUND, - PNG_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid user-defined image specifications. */ - -static struct image_keyword png_format[PNG_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":data", IMAGE_STRING_VALUE, 0}, - {":file", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 0}, - {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":background", IMAGE_STRING_OR_NIL_VALUE, 0} -}; - -/* Structure describing the image type `png'. */ - -static struct image_type png_type = -{ - &Qpng, - png_image_p, - png_load, - x_clear_image, - NULL -}; - -/* PNG library details. */ - -DEF_IMGLIB_FN (png_get_io_ptr); -DEF_IMGLIB_FN (png_check_sig); -DEF_IMGLIB_FN (png_create_read_struct); -DEF_IMGLIB_FN (png_create_info_struct); -DEF_IMGLIB_FN (png_destroy_read_struct); -DEF_IMGLIB_FN (png_set_read_fn); -DEF_IMGLIB_FN (png_init_io); -DEF_IMGLIB_FN (png_set_sig_bytes); -DEF_IMGLIB_FN (png_read_info); -DEF_IMGLIB_FN (png_get_IHDR); -DEF_IMGLIB_FN (png_get_valid); -DEF_IMGLIB_FN (png_set_strip_16); -DEF_IMGLIB_FN (png_set_expand); -DEF_IMGLIB_FN (png_set_gray_to_rgb); -DEF_IMGLIB_FN (png_set_background); -DEF_IMGLIB_FN (png_get_bKGD); -DEF_IMGLIB_FN (png_read_update_info); -DEF_IMGLIB_FN (png_get_channels); -DEF_IMGLIB_FN (png_get_rowbytes); -DEF_IMGLIB_FN (png_read_image); -DEF_IMGLIB_FN (png_read_end); -DEF_IMGLIB_FN (png_error); - -static int -init_png_functions (library) - HMODULE library; -{ - LOAD_IMGLIB_FN (library, png_get_io_ptr); - LOAD_IMGLIB_FN (library, png_check_sig); - LOAD_IMGLIB_FN (library, png_create_read_struct); - LOAD_IMGLIB_FN (library, png_create_info_struct); - LOAD_IMGLIB_FN (library, png_destroy_read_struct); - LOAD_IMGLIB_FN (library, png_set_read_fn); - LOAD_IMGLIB_FN (library, png_init_io); - LOAD_IMGLIB_FN (library, png_set_sig_bytes); - LOAD_IMGLIB_FN (library, png_read_info); - LOAD_IMGLIB_FN (library, png_get_IHDR); - LOAD_IMGLIB_FN (library, png_get_valid); - LOAD_IMGLIB_FN (library, png_set_strip_16); - LOAD_IMGLIB_FN (library, png_set_expand); - LOAD_IMGLIB_FN (library, png_set_gray_to_rgb); - LOAD_IMGLIB_FN (library, png_set_background); - LOAD_IMGLIB_FN (library, png_get_bKGD); - LOAD_IMGLIB_FN (library, png_read_update_info); - LOAD_IMGLIB_FN (library, png_get_channels); - LOAD_IMGLIB_FN (library, png_get_rowbytes); - LOAD_IMGLIB_FN (library, png_read_image); - LOAD_IMGLIB_FN (library, png_read_end); - LOAD_IMGLIB_FN (library, png_error); - return 1; -} - -/* Return non-zero if OBJECT is a valid PNG image specification. */ - -static int -png_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[PNG_LAST]; - bcopy (png_format, fmt, sizeof fmt); - - if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)) - return 0; - - /* Must specify either the :data or :file keyword. */ - return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1; -} - - -/* Error and warning handlers installed when the PNG library - is initialized. */ - -static void -my_png_error (png_ptr, msg) - png_struct *png_ptr; - char *msg; -{ - xassert (png_ptr != NULL); - image_error ("PNG error: %s", build_string (msg), Qnil); - longjmp (png_ptr->jmpbuf, 1); -} - - -static void -my_png_warning (png_ptr, msg) - png_struct *png_ptr; - char *msg; -{ - xassert (png_ptr != NULL); - image_error ("PNG warning: %s", build_string (msg), Qnil); -} - -/* Memory source for PNG decoding. */ - -struct png_memory_storage -{ - unsigned char *bytes; /* The data */ - size_t len; /* How big is it? */ - int index; /* Where are we? */ -}; - - -/* Function set as reader function when reading PNG image from memory. - PNG_PTR is a pointer to the PNG control structure. Copy LENGTH - bytes from the input to DATA. */ - -static void -png_read_from_memory (png_ptr, data, length) - png_structp png_ptr; - png_bytep data; - png_size_t length; -{ - struct png_memory_storage *tbr - = (struct png_memory_storage *) fn_png_get_io_ptr (png_ptr); - - if (length > tbr->len - tbr->index) - fn_png_error (png_ptr, "Read error"); - - bcopy (tbr->bytes + tbr->index, data, length); - tbr->index = tbr->index + length; -} - -/* Load PNG image IMG for use on frame F. Value is non-zero if - successful. */ - -static int -png_load (f, img) - struct frame *f; - struct image *img; -{ - Lisp_Object file, specified_file; - Lisp_Object specified_data; - int x, y, i; - XImage *ximg, *mask_img = NULL; - struct gcpro gcpro1; - png_struct *png_ptr = NULL; - png_info *info_ptr = NULL, *end_info = NULL; - FILE *volatile fp = NULL; - png_byte sig[8]; - png_byte * volatile pixels = NULL; - png_byte ** volatile rows = NULL; - png_uint_32 width, height; - int bit_depth, color_type, interlace_type; - png_byte channels; - png_uint_32 row_bytes; - int transparent_p; - double screen_gamma, image_gamma; - int intent; - struct png_memory_storage tbr; /* Data to be read */ - - /* Find out what file to load. */ - specified_file = image_spec_value (img->spec, QCfile, NULL); - specified_data = image_spec_value (img->spec, QCdata, NULL); - file = Qnil; - GCPRO1 (file); - - if (NILP (specified_data)) - { - file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNGCPRO; - return 0; - } - - /* Open the image file. */ - fp = fopen (SDATA (file), "rb"); - if (!fp) - { - image_error ("Cannot open image file `%s'", file, Qnil); - UNGCPRO; - fclose (fp); - return 0; - } - - /* Check PNG signature. */ - if (fread (sig, 1, sizeof sig, fp) != sizeof sig - || !fn_png_check_sig (sig, sizeof sig)) - { - image_error ("Not a PNG file: `%s'", file, Qnil); - UNGCPRO; - fclose (fp); - return 0; - } - } - else - { - /* Read from memory. */ - tbr.bytes = SDATA (specified_data); - tbr.len = SBYTES (specified_data); - tbr.index = 0; - - /* Check PNG signature. */ - if (tbr.len < sizeof sig - || !fn_png_check_sig (tbr.bytes, sizeof sig)) - { - image_error ("Not a PNG image: `%s'", img->spec, Qnil); - UNGCPRO; - return 0; - } - - /* Need to skip past the signature. */ - tbr.bytes += sizeof (sig); - } - - /* Initialize read and info structs for PNG lib. */ - png_ptr = fn_png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, - my_png_error, my_png_warning); - if (!png_ptr) - { - if (fp) fclose (fp); - UNGCPRO; - return 0; - } - - info_ptr = fn_png_create_info_struct (png_ptr); - if (!info_ptr) - { - fn_png_destroy_read_struct (&png_ptr, NULL, NULL); - if (fp) fclose (fp); - UNGCPRO; - return 0; - } - - end_info = fn_png_create_info_struct (png_ptr); - if (!end_info) - { - fn_png_destroy_read_struct (&png_ptr, &info_ptr, NULL); - if (fp) fclose (fp); - UNGCPRO; - return 0; - } - - /* Set error jump-back. We come back here when the PNG library - detects an error. */ - if (setjmp (png_ptr->jmpbuf)) - { - error: - if (png_ptr) - fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); - xfree (pixels); - xfree (rows); - if (fp) fclose (fp); - UNGCPRO; - return 0; - } - - /* Read image info. */ - if (!NILP (specified_data)) - fn_png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory); - else - fn_png_init_io (png_ptr, fp); - - fn_png_set_sig_bytes (png_ptr, sizeof sig); - fn_png_read_info (png_ptr, info_ptr); - fn_png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, - &interlace_type, NULL, NULL); - - /* If image contains simply transparency data, we prefer to - construct a clipping mask. */ - if (fn_png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) - transparent_p = 1; - else - transparent_p = 0; - - /* This function is easier to write if we only have to handle - one data format: RGB or RGBA with 8 bits per channel. Let's - transform other formats into that format. */ - - /* Strip more than 8 bits per channel. */ - if (bit_depth == 16) - fn_png_set_strip_16 (png_ptr); - - /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel - if available. */ - fn_png_set_expand (png_ptr); - - /* Convert grayscale images to RGB. */ - if (color_type == PNG_COLOR_TYPE_GRAY - || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - fn_png_set_gray_to_rgb (png_ptr); - - screen_gamma = (f->gamma ? 1 / f->gamma / 0.45455 : 2.2); - -#if 0 /* Avoid double gamma correction for PNG images. */ - /* Tell the PNG lib to handle gamma correction for us. */ -#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED) - if (png_get_sRGB (png_ptr, info_ptr, &intent)) - /* The libpng documentation says this is right in this case. */ - png_set_gamma (png_ptr, screen_gamma, 0.45455); - else -#endif - if (png_get_gAMA (png_ptr, info_ptr, &image_gamma)) - /* Image contains gamma information. */ - png_set_gamma (png_ptr, screen_gamma, image_gamma); - else - /* Use the standard default for the image gamma. */ - png_set_gamma (png_ptr, screen_gamma, 0.45455); -#endif /* if 0 */ - - /* Handle alpha channel by combining the image with a background - color. Do this only if a real alpha channel is supplied. For - simple transparency, we prefer a clipping mask. */ - if (!transparent_p) - { - png_color_16 *image_bg; - Lisp_Object specified_bg - = image_spec_value (img->spec, QCbackground, NULL); - - if (STRINGP (specified_bg)) - /* The user specified `:background', use that. */ - { - COLORREF color; - if (w32_defined_color (f, SDATA (specified_bg), &color, 0)) - { - png_color_16 user_bg; - - bzero (&user_bg, sizeof user_bg); - user_bg.red = 256 * GetRValue (color); - user_bg.green = 256 * GetGValue (color); - user_bg.blue = 256 * GetBValue (color); - - fn_png_set_background (png_ptr, &user_bg, - PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); - } - } - else if (fn_png_get_bKGD (png_ptr, info_ptr, &image_bg)) - /* Image contains a background color with which to - combine the image. */ - fn_png_set_background (png_ptr, image_bg, - PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); - else - { - /* Image does not contain a background color with which - to combine the image data via an alpha channel. Use - the frame's background instead. */ - COLORREF color; - png_color_16 frame_background; - color = FRAME_BACKGROUND_PIXEL (f); -#if 0 /* TODO : Colormap support. */ - Colormap cmap; - - cmap = FRAME_X_COLORMAP (f); - x_query_color (f, &color); -#endif - - bzero (&frame_background, sizeof frame_background); - frame_background.red = 256 * GetRValue (color); - frame_background.green = 256 * GetGValue (color); - frame_background.blue = 256 * GetBValue (color); - - fn_png_set_background (png_ptr, &frame_background, - PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); - } - } - - /* Update info structure. */ - fn_png_read_update_info (png_ptr, info_ptr); - - /* Get number of channels. Valid values are 1 for grayscale images - and images with a palette, 2 for grayscale images with transparency - information (alpha channel), 3 for RGB images, and 4 for RGB - images with alpha channel, i.e. RGBA. If conversions above were - sufficient we should only have 3 or 4 channels here. */ - channels = fn_png_get_channels (png_ptr, info_ptr); - xassert (channels == 3 || channels == 4); - - /* Number of bytes needed for one row of the image. */ - row_bytes = fn_png_get_rowbytes (png_ptr, info_ptr); - - /* Allocate memory for the image. */ - pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels); - rows = (png_byte **) xmalloc (height * sizeof *rows); - for (i = 0; i < height; ++i) - rows[i] = pixels + i * row_bytes; - - /* Read the entire image. */ - fn_png_read_image (png_ptr, rows); - fn_png_read_end (png_ptr, info_ptr); - if (fp) - { - fclose (fp); - fp = NULL; - } - - /* Create the X image and pixmap. */ - if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, - &img->pixmap)) - goto error; - - /* Create an image and pixmap serving as mask if the PNG image - contains an alpha channel. */ - if (channels == 4 - && !transparent_p - && !x_create_x_image_and_pixmap (f, width, height, 1, - &mask_img, &img->mask)) - { - x_destroy_x_image (ximg); - DeleteObject (img->pixmap); - img->pixmap = 0; - goto error; - } - /* Fill the X image and mask from PNG data. */ -#if 0 /* TODO: Color tables. */ - init_color_table (); -#endif - - for (y = 0; y < height; ++y) - { - png_byte *p = rows[y]; - - for (x = 0; x < width; ++x) - { - unsigned r, g, b; - - r = *p++; - g = *p++; - b = *p++; -#if 0 /* TODO: Color tables. */ - XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b)); -#else - XPutPixel (ximg, x, y, PALETTERGB (r, g, b)); -#endif - /* An alpha channel, aka mask channel, associates variable - transparency with an image. Where other image formats - support binary transparency---fully transparent or fully - opaque---PNG allows up to 254 levels of partial transparency. - The PNG library implements partial transparency by combining - the image with a specified background color. - - I'm not sure how to handle this here nicely: because the - background on which the image is displayed may change, for - real alpha channel support, it would be necessary to create - a new image for each possible background. - - What I'm doing now is that a mask is created if we have - boolean transparency information. Otherwise I'm using - the frame's background color to combine the image with. */ - - if (channels == 4) - { - if (mask_img) - XPutPixel (mask_img, x, y, *p > 0); - ++p; - } - } - } - - if (NILP (image_spec_value (img->spec, QCbackground, NULL))) - /* Set IMG's background color from the PNG image, unless the user - overrode it. */ - { - png_color_16 *bg; - if (fn_png_get_bKGD (png_ptr, info_ptr, &bg)) - { -#if 0 /* TODO: Color tables. */ - img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue); -#else - img->background = PALETTERGB (bg->red / 256, bg->green / 256, - bg->blue / 256); -#endif - img->background_valid = 1; - } - } - -#if 0 /* TODO: Color tables. */ - /* Remember colors allocated for this image. */ - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); -#endif - - /* Clean up. */ - fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); - xfree (rows); - xfree (pixels); - - img->width = width; - img->height = height; - - /* Maybe fill in the background field while we have ximg handy. */ - IMAGE_BACKGROUND (img, f, ximg); - - /* Put the image into the pixmap, then free the X image and its buffer. */ - x_put_x_image (f, ximg, img->pixmap, width, height); - x_destroy_x_image (ximg); - - /* Same for the mask. */ - if (mask_img) - { - /* Fill in the background_transparent field while we have the mask - handy. */ - image_background_transparent (img, f, mask_img); - - x_put_x_image (f, mask_img, img->mask, img->width, img->height); - x_destroy_x_image (mask_img); - } - - UNGCPRO; - return 1; -} - -#endif /* HAVE_PNG != 0 */ - - - -/*********************************************************************** - JPEG - ***********************************************************************/ - -#if HAVE_JPEG - -/* Work around a warning about HAVE_STDLIB_H being redefined in - jconfig.h. */ -#ifdef HAVE_STDLIB_H -#define HAVE_STDLIB_H_1 -#undef HAVE_STDLIB_H -#endif /* HAVE_STLIB_H */ - -#include <jpeglib.h> -#include <jerror.h> -#include <setjmp.h> - -#ifdef HAVE_STLIB_H_1 -#define HAVE_STDLIB_H 1 -#endif - -static int jpeg_image_p P_ ((Lisp_Object object)); -static int jpeg_load P_ ((struct frame *f, struct image *img)); - -/* The symbol `jpeg' identifying images of this type. */ - -Lisp_Object Qjpeg; - -/* Indices of image specification fields in gs_format, below. */ - -enum jpeg_keyword_index -{ - JPEG_TYPE, - JPEG_DATA, - JPEG_FILE, - JPEG_ASCENT, - JPEG_MARGIN, - JPEG_RELIEF, - JPEG_ALGORITHM, - JPEG_HEURISTIC_MASK, - JPEG_MASK, - JPEG_BACKGROUND, - JPEG_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid user-defined image specifications. */ - -static struct image_keyword jpeg_format[JPEG_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":data", IMAGE_STRING_VALUE, 0}, - {":file", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 0}, - {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":background", IMAGE_STRING_OR_NIL_VALUE, 0} -}; - -/* Structure describing the image type `jpeg'. */ - -static struct image_type jpeg_type = -{ - &Qjpeg, - jpeg_image_p, - jpeg_load, - x_clear_image, - NULL -}; - - -/* JPEG library details. */ -DEF_IMGLIB_FN (jpeg_CreateDecompress); -DEF_IMGLIB_FN (jpeg_start_decompress); -DEF_IMGLIB_FN (jpeg_finish_decompress); -DEF_IMGLIB_FN (jpeg_destroy_decompress); -DEF_IMGLIB_FN (jpeg_read_header); -DEF_IMGLIB_FN (jpeg_read_scanlines); -DEF_IMGLIB_FN (jpeg_stdio_src); -DEF_IMGLIB_FN (jpeg_std_error); -DEF_IMGLIB_FN (jpeg_resync_to_restart); - -static int -init_jpeg_functions (library) - HMODULE library; -{ - LOAD_IMGLIB_FN (library, jpeg_finish_decompress); - LOAD_IMGLIB_FN (library, jpeg_read_scanlines); - LOAD_IMGLIB_FN (library, jpeg_start_decompress); - LOAD_IMGLIB_FN (library, jpeg_read_header); - LOAD_IMGLIB_FN (library, jpeg_stdio_src); - LOAD_IMGLIB_FN (library, jpeg_CreateDecompress); - LOAD_IMGLIB_FN (library, jpeg_destroy_decompress); - LOAD_IMGLIB_FN (library, jpeg_std_error); - LOAD_IMGLIB_FN (library, jpeg_resync_to_restart); - return 1; -} - -/* Wrapper since we can't directly assign the function pointer - to another function pointer that was declared more completely easily. */ -static boolean -jpeg_resync_to_restart_wrapper(cinfo, desired) - j_decompress_ptr cinfo; - int desired; -{ - return fn_jpeg_resync_to_restart (cinfo, desired); -} - - -/* Return non-zero if OBJECT is a valid JPEG image specification. */ - -static int -jpeg_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[JPEG_LAST]; - - bcopy (jpeg_format, fmt, sizeof fmt); - - if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)) - return 0; - - /* Must specify either the :data or :file keyword. */ - return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1; -} - - -struct my_jpeg_error_mgr -{ - struct jpeg_error_mgr pub; - jmp_buf setjmp_buffer; -}; - - -static void -my_error_exit (cinfo) - j_common_ptr cinfo; -{ - struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err; - longjmp (mgr->setjmp_buffer, 1); -} - - -/* Init source method for JPEG data source manager. Called by - jpeg_read_header() before any data is actually read. See - libjpeg.doc from the JPEG lib distribution. */ - -static void -our_init_source (cinfo) - j_decompress_ptr cinfo; -{ -} - - -/* Fill input buffer method for JPEG data source manager. Called - whenever more data is needed. We read the whole image in one step, - so this only adds a fake end of input marker at the end. */ - -static boolean -our_fill_input_buffer (cinfo) - j_decompress_ptr cinfo; -{ - /* Insert a fake EOI marker. */ - struct jpeg_source_mgr *src = cinfo->src; - static JOCTET buffer[2]; - - buffer[0] = (JOCTET) 0xFF; - buffer[1] = (JOCTET) JPEG_EOI; - - src->next_input_byte = buffer; - src->bytes_in_buffer = 2; - return TRUE; -} - - -/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src - is the JPEG data source manager. */ - -static void -our_skip_input_data (cinfo, num_bytes) - j_decompress_ptr cinfo; - long num_bytes; -{ - struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src; - - if (src) - { - if (num_bytes > src->bytes_in_buffer) - ERREXIT (cinfo, JERR_INPUT_EOF); - - src->bytes_in_buffer -= num_bytes; - src->next_input_byte += num_bytes; - } -} - - -/* Method to terminate data source. Called by - jpeg_finish_decompress() after all data has been processed. */ - -static void -our_term_source (cinfo) - j_decompress_ptr cinfo; -{ -} - - -/* Set up the JPEG lib for reading an image from DATA which contains - LEN bytes. CINFO is the decompression info structure created for - reading the image. */ - -static void -jpeg_memory_src (cinfo, data, len) - j_decompress_ptr cinfo; - JOCTET *data; - unsigned int len; -{ - struct jpeg_source_mgr *src; - - if (cinfo->src == NULL) - { - /* First time for this JPEG object? */ - cinfo->src = (struct jpeg_source_mgr *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - sizeof (struct jpeg_source_mgr)); - src = (struct jpeg_source_mgr *) cinfo->src; - src->next_input_byte = data; - } - - src = (struct jpeg_source_mgr *) cinfo->src; - src->init_source = our_init_source; - src->fill_input_buffer = our_fill_input_buffer; - src->skip_input_data = our_skip_input_data; - src->resync_to_restart = jpeg_resync_to_restart_wrapper; /* Use default method. */ - src->term_source = our_term_source; - src->bytes_in_buffer = len; - src->next_input_byte = data; -} - - -/* Load image IMG for use on frame F. Patterned after example.c - from the JPEG lib. */ - -static int -jpeg_load (f, img) - struct frame *f; - struct image *img; -{ - struct jpeg_decompress_struct cinfo; - struct my_jpeg_error_mgr mgr; - Lisp_Object file, specified_file; - Lisp_Object specified_data; - FILE * volatile fp = NULL; - JSAMPARRAY buffer; - int row_stride, x, y; - XImage *ximg = NULL; - int rc; - unsigned long *colors; - int width, height; - struct gcpro gcpro1; - - /* Open the JPEG file. */ - specified_file = image_spec_value (img->spec, QCfile, NULL); - specified_data = image_spec_value (img->spec, QCdata, NULL); - file = Qnil; - GCPRO1 (file); - - if (NILP (specified_data)) - { - file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNGCPRO; - return 0; - } - - fp = fopen (SDATA (file), "rb"); - if (fp == NULL) - { - image_error ("Cannot open `%s'", file, Qnil); - UNGCPRO; - return 0; - } - } - - /* Customize libjpeg's error handling to call my_error_exit when an - error is detected. This function will perform a longjmp. */ - cinfo.err = fn_jpeg_std_error (&mgr.pub); - mgr.pub.error_exit = my_error_exit; - - if ((rc = setjmp (mgr.setjmp_buffer)) != 0) - { - if (rc == 1) - { - /* Called from my_error_exit. Display a JPEG error. */ - char buffer[JMSG_LENGTH_MAX]; - cinfo.err->format_message ((j_common_ptr) &cinfo, buffer); - image_error ("Error reading JPEG image `%s': %s", img->spec, - build_string (buffer)); - } - - /* Close the input file and destroy the JPEG object. */ - if (fp) - fclose ((FILE *) fp); - fn_jpeg_destroy_decompress (&cinfo); - - /* If we already have an XImage, free that. */ - x_destroy_x_image (ximg); - - /* Free pixmap and colors. */ - x_clear_image (f, img); - - UNGCPRO; - return 0; - } - - /* Create the JPEG decompression object. Let it read from fp. - Read the JPEG image header. */ - fn_jpeg_CreateDecompress (&cinfo, JPEG_LIB_VERSION, sizeof (cinfo)); - - if (NILP (specified_data)) - fn_jpeg_stdio_src (&cinfo, (FILE *) fp); - else - jpeg_memory_src (&cinfo, SDATA (specified_data), - SBYTES (specified_data)); - - fn_jpeg_read_header (&cinfo, TRUE); - - /* Customize decompression so that color quantization will be used. - Start decompression. */ - cinfo.quantize_colors = TRUE; - fn_jpeg_start_decompress (&cinfo); - width = img->width = cinfo.output_width; - height = img->height = cinfo.output_height; - - /* Create X image and pixmap. */ - if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) - longjmp (mgr.setjmp_buffer, 2); - - /* Allocate colors. When color quantization is used, - cinfo.actual_number_of_colors has been set with the number of - colors generated, and cinfo.colormap is a two-dimensional array - of color indices in the range 0..cinfo.actual_number_of_colors. - No more than 255 colors will be generated. */ - { - int i, ir, ig, ib; - - if (cinfo.out_color_components > 2) - ir = 0, ig = 1, ib = 2; - else if (cinfo.out_color_components > 1) - ir = 0, ig = 1, ib = 0; - else - ir = 0, ig = 0, ib = 0; - -#if 0 /* TODO: Color tables. */ - /* Use the color table mechanism because it handles colors that - cannot be allocated nicely. Such colors will be replaced with - a default color, and we don't have to care about which colors - can be freed safely, and which can't. */ - init_color_table (); -#endif - colors = (unsigned long *) alloca (cinfo.actual_number_of_colors - * sizeof *colors); - - for (i = 0; i < cinfo.actual_number_of_colors; ++i) - { - int r = cinfo.colormap[ir][i]; - int g = cinfo.colormap[ig][i]; - int b = cinfo.colormap[ib][i]; -#if 0 /* TODO: Color tables. */ - colors[i] = lookup_rgb_color (f, r, g, b); -#else - colors[i] = PALETTERGB (r, g, b); -#endif - } - -#if 0 /* TODO: Color tables. */ - /* Remember those colors actually allocated. */ - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); -#endif - } - - /* Read pixels. */ - row_stride = width * cinfo.output_components; - buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE, - row_stride, 1); - for (y = 0; y < height; ++y) - { - fn_jpeg_read_scanlines (&cinfo, buffer, 1); - for (x = 0; x < cinfo.output_width; ++x) - XPutPixel (ximg, x, y, colors[buffer[0][x]]); - } - - /* Clean up. */ - fn_jpeg_finish_decompress (&cinfo); - fn_jpeg_destroy_decompress (&cinfo); - if (fp) - fclose ((FILE *) fp); - - /* Maybe fill in the background field while we have ximg handy. */ - if (NILP (image_spec_value (img->spec, QCbackground, NULL))) - IMAGE_BACKGROUND (img, f, ximg); - - /* Put the image into the pixmap. */ - x_put_x_image (f, ximg, img->pixmap, width, height); - x_destroy_x_image (ximg); - UNGCPRO; - return 1; -} - -#endif /* HAVE_JPEG */ - - - -/*********************************************************************** - TIFF - ***********************************************************************/ - -#if HAVE_TIFF - -#include <tiffio.h> - -static int tiff_image_p P_ ((Lisp_Object object)); -static int tiff_load P_ ((struct frame *f, struct image *img)); - -/* The symbol `tiff' identifying images of this type. */ - -Lisp_Object Qtiff; - -/* Indices of image specification fields in tiff_format, below. */ - -enum tiff_keyword_index -{ - TIFF_TYPE, - TIFF_DATA, - TIFF_FILE, - TIFF_ASCENT, - TIFF_MARGIN, - TIFF_RELIEF, - TIFF_ALGORITHM, - TIFF_HEURISTIC_MASK, - TIFF_MASK, - TIFF_BACKGROUND, - TIFF_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid user-defined image specifications. */ - -static struct image_keyword tiff_format[TIFF_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":data", IMAGE_STRING_VALUE, 0}, - {":file", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 0}, - {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":background", IMAGE_STRING_OR_NIL_VALUE, 0} -}; - -/* Structure describing the image type `tiff'. */ - -static struct image_type tiff_type = -{ - &Qtiff, - tiff_image_p, - tiff_load, - x_clear_image, - NULL -}; - -/* TIFF library details. */ -DEF_IMGLIB_FN (TIFFSetErrorHandler); -DEF_IMGLIB_FN (TIFFSetWarningHandler); -DEF_IMGLIB_FN (TIFFOpen); -DEF_IMGLIB_FN (TIFFClientOpen); -DEF_IMGLIB_FN (TIFFGetField); -DEF_IMGLIB_FN (TIFFReadRGBAImage); -DEF_IMGLIB_FN (TIFFClose); - -static int -init_tiff_functions (library) - HMODULE library; -{ - LOAD_IMGLIB_FN (library, TIFFSetErrorHandler); - LOAD_IMGLIB_FN (library, TIFFSetWarningHandler); - LOAD_IMGLIB_FN (library, TIFFOpen); - LOAD_IMGLIB_FN (library, TIFFClientOpen); - LOAD_IMGLIB_FN (library, TIFFGetField); - LOAD_IMGLIB_FN (library, TIFFReadRGBAImage); - LOAD_IMGLIB_FN (library, TIFFClose); - return 1; -} - -/* Return non-zero if OBJECT is a valid TIFF image specification. */ - -static int -tiff_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[TIFF_LAST]; - bcopy (tiff_format, fmt, sizeof fmt); - - if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)) - return 0; - - /* Must specify either the :data or :file keyword. */ - return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1; -} - - -/* Reading from a memory buffer for TIFF images Based on the PNG - memory source, but we have to provide a lot of extra functions. - Blah. - - We really only need to implement read and seek, but I am not - convinced that the TIFF library is smart enough not to destroy - itself if we only hand it the function pointers we need to - override. */ - -typedef struct -{ - unsigned char *bytes; - size_t len; - int index; -} -tiff_memory_source; - -static size_t -tiff_read_from_memory (data, buf, size) - thandle_t data; - tdata_t buf; - tsize_t size; -{ - tiff_memory_source *src = (tiff_memory_source *) data; - - if (size > src->len - src->index) - return (size_t) -1; - bcopy (src->bytes + src->index, buf, size); - src->index += size; - return size; -} - -static size_t -tiff_write_from_memory (data, buf, size) - thandle_t data; - tdata_t buf; - tsize_t size; -{ - return (size_t) -1; -} - -static toff_t -tiff_seek_in_memory (data, off, whence) - thandle_t data; - toff_t off; - int whence; -{ - tiff_memory_source *src = (tiff_memory_source *) data; - int idx; - - switch (whence) - { - case SEEK_SET: /* Go from beginning of source. */ - idx = off; - break; - - case SEEK_END: /* Go from end of source. */ - idx = src->len + off; - break; - - case SEEK_CUR: /* Go from current position. */ - idx = src->index + off; - break; - - default: /* Invalid `whence'. */ - return -1; - } - - if (idx > src->len || idx < 0) - return -1; - - src->index = idx; - return src->index; -} - -static int -tiff_close_memory (data) - thandle_t data; -{ - /* NOOP */ - return 0; -} - -static int -tiff_mmap_memory (data, pbase, psize) - thandle_t data; - tdata_t *pbase; - toff_t *psize; -{ - /* It is already _IN_ memory. */ - return 0; -} - -static void -tiff_unmap_memory (data, base, size) - thandle_t data; - tdata_t base; - toff_t size; -{ - /* We don't need to do this. */ -} - -static toff_t -tiff_size_of_memory (data) - thandle_t data; -{ - return ((tiff_memory_source *) data)->len; -} - - -static void -tiff_error_handler (title, format, ap) - const char *title, *format; - va_list ap; -{ - char buf[512]; - int len; - - len = sprintf (buf, "TIFF error: %s ", title); - vsprintf (buf + len, format, ap); - add_to_log (buf, Qnil, Qnil); -} - - -static void -tiff_warning_handler (title, format, ap) - const char *title, *format; - va_list ap; -{ - char buf[512]; - int len; - - len = sprintf (buf, "TIFF warning: %s ", title); - vsprintf (buf + len, format, ap); - add_to_log (buf, Qnil, Qnil); -} - - -/* Load TIFF image IMG for use on frame F. Value is non-zero if - successful. */ - -static int -tiff_load (f, img) - struct frame *f; - struct image *img; -{ - Lisp_Object file, specified_file; - Lisp_Object specified_data; - TIFF *tiff; - int width, height, x, y; - uint32 *buf; - int rc; - XImage *ximg; - struct gcpro gcpro1; - tiff_memory_source memsrc; - - specified_file = image_spec_value (img->spec, QCfile, NULL); - specified_data = image_spec_value (img->spec, QCdata, NULL); - file = Qnil; - GCPRO1 (file); - - fn_TIFFSetErrorHandler (tiff_error_handler); - fn_TIFFSetWarningHandler (tiff_warning_handler); - - if (NILP (specified_data)) - { - /* Read from a file */ - file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", file, Qnil); - UNGCPRO; - return 0; - } - - /* Try to open the image file. */ - tiff = fn_TIFFOpen (SDATA (file), "r"); - if (tiff == NULL) - { - image_error ("Cannot open `%s'", file, Qnil); - UNGCPRO; - return 0; - } - } - else - { - /* Memory source! */ - memsrc.bytes = SDATA (specified_data); - memsrc.len = SBYTES (specified_data); - memsrc.index = 0; - - tiff = fn_TIFFClientOpen ("memory_source", "r", &memsrc, - (TIFFReadWriteProc) tiff_read_from_memory, - (TIFFReadWriteProc) tiff_write_from_memory, - tiff_seek_in_memory, - tiff_close_memory, - tiff_size_of_memory, - tiff_mmap_memory, - tiff_unmap_memory); - - if (!tiff) - { - image_error ("Cannot open memory source for `%s'", img->spec, Qnil); - UNGCPRO; - return 0; - } - } - - /* Get width and height of the image, and allocate a raster buffer - of width x height 32-bit values. */ - fn_TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width); - fn_TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height); - buf = (uint32 *) xmalloc (width * height * sizeof *buf); - - rc = fn_TIFFReadRGBAImage (tiff, width, height, buf, 0); - fn_TIFFClose (tiff); - if (!rc) - { - image_error ("Error reading TIFF image `%s'", img->spec, Qnil); - xfree (buf); - UNGCPRO; - return 0; - } - - /* Create the X image and pixmap. */ - if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) - { - xfree (buf); - UNGCPRO; - return 0; - } - -#if 0 /* TODO: Color tables. */ - /* Initialize the color table. */ - init_color_table (); -#endif - - /* Process the pixel raster. Origin is in the lower-left corner. */ - for (y = 0; y < height; ++y) - { - uint32 *row = buf + y * width; - - for (x = 0; x < width; ++x) - { - uint32 abgr = row[x]; - int r = TIFFGetR (abgr); - int g = TIFFGetG (abgr); - int b = TIFFGetB (abgr); -#if 0 /* TODO: Color tables. */ - XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b)); -#else - XPutPixel (ximg, x, height - 1 - y, PALETTERGB (r, g, b)); -#endif - } - } - -#if 0 /* TODO: Color tables. */ - /* Remember the colors allocated for the image. Free the color table. */ - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); -#endif - - img->width = width; - img->height = height; - - /* Maybe fill in the background field while we have ximg handy. */ - if (NILP (image_spec_value (img->spec, QCbackground, NULL))) - IMAGE_BACKGROUND (img, f, ximg); - - /* Put the image into the pixmap, then free the X image and its buffer. */ - x_put_x_image (f, ximg, img->pixmap, width, height); - x_destroy_x_image (ximg); - xfree (buf); - - UNGCPRO; - return 1; -} - -#endif /* HAVE_TIFF != 0 */ - - - -/*********************************************************************** - GIF - ***********************************************************************/ - -#if HAVE_GIF - -#define DrawText gif_DrawText -#include <gif_lib.h> -#undef DrawText - -static int gif_image_p P_ ((Lisp_Object object)); -static int gif_load P_ ((struct frame *f, struct image *img)); - -/* The symbol `gif' identifying images of this type. */ - -Lisp_Object Qgif; - -/* Indices of image specification fields in gif_format, below. */ - -enum gif_keyword_index -{ - GIF_TYPE, - GIF_DATA, - GIF_FILE, - GIF_ASCENT, - GIF_MARGIN, - GIF_RELIEF, - GIF_ALGORITHM, - GIF_HEURISTIC_MASK, - GIF_MASK, - GIF_IMAGE, - GIF_BACKGROUND, - GIF_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid user-defined image specifications. */ - -static struct image_keyword gif_format[GIF_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":data", IMAGE_STRING_VALUE, 0}, - {":file", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 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}, - {":background", IMAGE_STRING_OR_NIL_VALUE, 0} -}; - -/* Structure describing the image type `gif'. */ - -static struct image_type gif_type = -{ - &Qgif, - gif_image_p, - gif_load, - x_clear_image, - NULL -}; - - -/* GIF library details. */ -DEF_IMGLIB_FN (DGifCloseFile); -DEF_IMGLIB_FN (DGifSlurp); -DEF_IMGLIB_FN (DGifOpen); -DEF_IMGLIB_FN (DGifOpenFileName); - -static int -init_gif_functions (library) - HMODULE library; -{ - LOAD_IMGLIB_FN (library, DGifCloseFile); - LOAD_IMGLIB_FN (library, DGifSlurp); - LOAD_IMGLIB_FN (library, DGifOpen); - LOAD_IMGLIB_FN (library, DGifOpenFileName); - return 1; -} - - -/* Return non-zero if OBJECT is a valid GIF image specification. */ - -static int -gif_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[GIF_LAST]; - bcopy (gif_format, fmt, sizeof fmt); - - if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)) - return 0; - - /* Must specify either the :data or :file keyword. */ - return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1; -} - -/* Reading a GIF image from memory - Based on the PNG memory stuff to a certain extent. */ - -typedef struct -{ - unsigned char *bytes; - size_t len; - int index; -} -gif_memory_source; - -/* Make the current memory source available to gif_read_from_memory. - It's done this way because not all versions of libungif support - a UserData field in the GifFileType structure. */ -static gif_memory_source *current_gif_memory_src; - -static int -gif_read_from_memory (file, buf, len) - GifFileType *file; - GifByteType *buf; - int len; -{ - gif_memory_source *src = current_gif_memory_src; - - if (len > src->len - src->index) - return -1; - - bcopy (src->bytes + src->index, buf, len); - src->index += len; - return len; -} - - -/* Load GIF image IMG for use on frame F. Value is non-zero if - successful. */ - -static int -gif_load (f, img) - struct frame *f; - struct image *img; -{ - Lisp_Object file, specified_file; - Lisp_Object specified_data; - int rc, width, height, x, y, i; - XImage *ximg; - ColorMapObject *gif_color_map; - unsigned long pixel_colors[256]; - GifFileType *gif; - struct gcpro gcpro1; - Lisp_Object image; - int ino, image_left, image_top, image_width, image_height; - gif_memory_source memsrc; - unsigned char *raster; - - specified_file = image_spec_value (img->spec, QCfile, NULL); - specified_data = image_spec_value (img->spec, QCdata, NULL); - file = Qnil; - GCPRO1 (file); - - if (NILP (specified_data)) - { - file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNGCPRO; - return 0; - } - - /* Open the GIF file. */ - gif = fn_DGifOpenFileName (SDATA (file)); - if (gif == NULL) - { - image_error ("Cannot open `%s'", file, Qnil); - UNGCPRO; - return 0; - } - } - else - { - /* Read from memory! */ - current_gif_memory_src = &memsrc; - memsrc.bytes = SDATA (specified_data); - memsrc.len = SBYTES (specified_data); - memsrc.index = 0; - - gif = fn_DGifOpen(&memsrc, gif_read_from_memory); - if (!gif) - { - image_error ("Cannot open memory source `%s'", img->spec, Qnil); - UNGCPRO; - return 0; - } - } - - /* Read entire contents. */ - rc = fn_DGifSlurp (gif); - if (rc == GIF_ERROR) - { - image_error ("Error reading `%s'", img->spec, Qnil); - fn_DGifCloseFile (gif); - UNGCPRO; - return 0; - } - - image = image_spec_value (img->spec, QCindex, NULL); - ino = INTEGERP (image) ? XFASTINT (image) : 0; - if (ino >= gif->ImageCount) - { - image_error ("Invalid image number `%s' in image `%s'", - image, img->spec); - fn_DGifCloseFile (gif); - UNGCPRO; - return 0; - } - - width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width); - height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height); - - /* Create the X image and pixmap. */ - if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) - { - fn_DGifCloseFile (gif); - UNGCPRO; - return 0; - } - - /* Allocate colors. */ - gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap; - if (!gif_color_map) - gif_color_map = gif->SColorMap; -#if 0 /* TODO: Color tables */ - init_color_table (); -#endif - bzero (pixel_colors, sizeof pixel_colors); - - for (i = 0; i < gif_color_map->ColorCount; ++i) - { - int r = gif_color_map->Colors[i].Red; - int g = gif_color_map->Colors[i].Green; - int b = gif_color_map->Colors[i].Blue; -#if 0 /* TODO: Color tables */ - pixel_colors[i] = lookup_rgb_color (f, r, g, b); -#else - pixel_colors[i] = PALETTERGB (r, g, b); -#endif - } - -#if 0 /* TODO: Color tables */ - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); -#endif - - /* Clear the part of the screen image that are not covered by - the image from the GIF file. Full animated GIF support - requires more than can be done here (see the gif89 spec, - disposal methods). Let's simply assume that the part - not covered by a sub-image is in the frame's background color. */ - image_top = gif->SavedImages[ino].ImageDesc.Top; - image_left = gif->SavedImages[ino].ImageDesc.Left; - image_width = gif->SavedImages[ino].ImageDesc.Width; - image_height = gif->SavedImages[ino].ImageDesc.Height; - - for (y = 0; y < image_top; ++y) - for (x = 0; x < width; ++x) - XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); - - for (y = image_top + image_height; y < height; ++y) - for (x = 0; x < width; ++x) - XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); - - for (y = image_top; y < image_top + image_height; ++y) - { - for (x = 0; x < image_left; ++x) - XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); - for (x = image_left + image_width; x < width; ++x) - XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); - } - - /* Read the GIF image into the X image. We use a local variable - `raster' here because RasterBits below is a char *, and invites - problems with bytes >= 0x80. */ - raster = (unsigned char *) gif->SavedImages[ino].RasterBits; - - if (gif->SavedImages[ino].ImageDesc.Interlace) - { - static int interlace_start[] = {0, 4, 2, 1}; - static int interlace_increment[] = {8, 8, 4, 2}; - int pass; - int row = interlace_start[0]; - - pass = 0; - - for (y = 0; y < image_height; y++) - { - if (row >= image_height) - { - row = interlace_start[++pass]; - while (row >= image_height) - row = interlace_start[++pass]; - } - - for (x = 0; x < image_width; x++) - { - int i = raster[(y * image_width) + x]; - XPutPixel (ximg, x + image_left, row + image_top, - pixel_colors[i]); - } - - row += interlace_increment[pass]; - } - } - else - { - for (y = 0; y < image_height; ++y) - for (x = 0; x < image_width; ++x) - { - int i = raster[y* image_width + x]; - XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]); - } - } - - fn_DGifCloseFile (gif); - - /* Maybe fill in the background field while we have ximg handy. */ - if (NILP (image_spec_value (img->spec, QCbackground, NULL))) - IMAGE_BACKGROUND (img, f, ximg); - - /* Put the image into the pixmap, then free the X image and its buffer. */ - x_put_x_image (f, ximg, img->pixmap, width, height); - x_destroy_x_image (ximg); - - UNGCPRO; - return 1; -} - -#endif /* HAVE_GIF != 0 */ - - - -/*********************************************************************** - Ghostscript - ***********************************************************************/ - -Lisp_Object Qpostscript; - -/* Keyword symbols. */ - -Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height; - -#ifdef HAVE_GHOSTSCRIPT -static int gs_image_p P_ ((Lisp_Object object)); -static int gs_load P_ ((struct frame *f, struct image *img)); -static void gs_clear_image P_ ((struct frame *f, struct image *img)); - -/* The symbol `postscript' identifying images of this type. */ - -/* Keyword symbols. */ - -Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height; - -/* Indices of image specification fields in gs_format, below. */ - -enum gs_keyword_index -{ - GS_TYPE, - GS_PT_WIDTH, - GS_PT_HEIGHT, - GS_FILE, - GS_LOADER, - GS_BOUNDING_BOX, - GS_ASCENT, - GS_MARGIN, - GS_RELIEF, - GS_ALGORITHM, - GS_HEURISTIC_MASK, - GS_MASK, - GS_BACKGROUND, - GS_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid user-defined image specifications. */ - -static struct image_keyword gs_format[GS_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1}, - {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1}, - {":file", IMAGE_STRING_VALUE, 1}, - {":loader", IMAGE_FUNCTION_VALUE, 0}, - {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1}, - {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 0}, - {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":background", IMAGE_STRING_OR_NIL_VALUE, 0} -}; - -/* Structure describing the image type `ghostscript'. */ - -static struct image_type gs_type = -{ - &Qpostscript, - gs_image_p, - gs_load, - gs_clear_image, - NULL -}; - - -/* Free X resources of Ghostscript image IMG which is used on frame F. */ - -static void -gs_clear_image (f, img) - struct frame *f; - struct image *img; -{ - /* IMG->data.ptr_val may contain a recorded colormap. */ - xfree (img->data.ptr_val); - x_clear_image (f, img); -} - - -/* Return non-zero if OBJECT is a valid Ghostscript image - specification. */ - -static int -gs_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[GS_LAST]; - Lisp_Object tem; - int i; - - bcopy (gs_format, fmt, sizeof fmt); - - if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)) - return 0; - - /* Bounding box must be a list or vector containing 4 integers. */ - tem = fmt[GS_BOUNDING_BOX].value; - if (CONSP (tem)) - { - for (i = 0; i < 4; ++i, tem = XCDR (tem)) - if (!CONSP (tem) || !INTEGERP (XCAR (tem))) - return 0; - if (!NILP (tem)) - return 0; - } - else if (VECTORP (tem)) - { - if (XVECTOR (tem)->size != 4) - return 0; - for (i = 0; i < 4; ++i) - if (!INTEGERP (XVECTOR (tem)->contents[i])) - return 0; - } - else - return 0; - - return 1; -} - - -/* Load Ghostscript image IMG for use on frame F. Value is non-zero - if successful. */ - -static int -gs_load (f, img) - struct frame *f; - struct image *img; -{ - char buffer[100]; - Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width; - struct gcpro gcpro1, gcpro2; - Lisp_Object frame; - double in_width, in_height; - Lisp_Object pixel_colors = Qnil; - - /* Compute pixel size of pixmap needed from the given size in the - image specification. Sizes in the specification are in pt. 1 pt - = 1/72 in, xdpi and ydpi are stored in the frame's X display - info. */ - pt_width = image_spec_value (img->spec, QCpt_width, NULL); - in_width = XFASTINT (pt_width) / 72.0; - img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx; - pt_height = image_spec_value (img->spec, QCpt_height, NULL); - in_height = XFASTINT (pt_height) / 72.0; - img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy; - - /* Create the pixmap. */ - BLOCK_INPUT; - xassert (img->pixmap == 0); - img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), - img->width, img->height, - one_w32_display_info.n_cbits); - UNBLOCK_INPUT; - - if (!img->pixmap) - { - image_error ("Unable to create pixmap for `%s'", img->spec, Qnil); - return 0; - } - - /* Call the loader to fill the pixmap. It returns a process object - if successful. We do not record_unwind_protect here because - other places in redisplay like calling window scroll functions - don't either. Let the Lisp loader use `unwind-protect' instead. */ - GCPRO2 (window_and_pixmap_id, pixel_colors); - - sprintf (buffer, "%lu %lu", - (unsigned long) FRAME_W32_WINDOW (f), - (unsigned long) img->pixmap); - window_and_pixmap_id = build_string (buffer); - - sprintf (buffer, "%lu %lu", - FRAME_FOREGROUND_PIXEL (f), - FRAME_BACKGROUND_PIXEL (f)); - pixel_colors = build_string (buffer); - - XSETFRAME (frame, f); - loader = image_spec_value (img->spec, QCloader, NULL); - if (NILP (loader)) - loader = intern ("gs-load-image"); - - img->data.lisp_val = call6 (loader, frame, img->spec, - make_number (img->width), - make_number (img->height), - window_and_pixmap_id, - pixel_colors); - UNGCPRO; - return PROCESSP (img->data.lisp_val); -} - - -/* Kill the Ghostscript process that was started to fill PIXMAP on - frame F. Called from XTread_socket when receiving an event - telling Emacs that Ghostscript has finished drawing. */ - -void -x_kill_gs_process (pixmap, f) - Pixmap pixmap; - struct frame *f; -{ - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - int class, i; - struct image *img; - - /* Find the image containing PIXMAP. */ - for (i = 0; i < c->used; ++i) - if (c->images[i]->pixmap == pixmap) - break; - - /* Should someone in between have cleared the image cache, for - instance, give up. */ - if (i == c->used) - return; - - /* Kill the GS process. We should have found PIXMAP in the image - cache and its image should contain a process object. */ - img = c->images[i]; - xassert (PROCESSP (img->data.lisp_val)); - Fkill_process (img->data.lisp_val, Qnil); - img->data.lisp_val = Qnil; - - /* On displays with a mutable colormap, figure out the colors - allocated for the image by looking at the pixels of an XImage for - img->pixmap. */ - class = FRAME_W32_DISPLAY_INFO (f)->visual->class; - if (class != StaticColor && class != StaticGray && class != TrueColor) - { - XImage *ximg; - - BLOCK_INPUT; - - /* Try to get an XImage for img->pixmep. */ - ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap, - 0, 0, img->width, img->height, ~0, ZPixmap); - if (ximg) - { - int x, y; - - /* Initialize the color table. */ - init_color_table (); - - /* For each pixel of the image, look its color up in the - color table. After having done so, the color table will - contain an entry for each color used by the image. */ - for (y = 0; y < img->height; ++y) - for (x = 0; x < img->width; ++x) - { - unsigned long pixel = XGetPixel (ximg, x, y); - lookup_pixel_color (f, pixel); - } - - /* Record colors in the image. Free color table and XImage. */ - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); - XDestroyImage (ximg); - -#if 0 /* This doesn't seem to be the case. If we free the colors - here, we get a BadAccess later in x_clear_image when - freeing the colors. */ - /* We have allocated colors once, but Ghostscript has also - allocated colors on behalf of us. So, to get the - reference counts right, free them once. */ - if (img->ncolors) - x_free_colors (FRAME_W32_DISPLAY (f), cmap, - img->colors, img->ncolors, 0); -#endif - } - else - image_error ("Cannot get X image of `%s'; colors will not be freed", - img->spec, Qnil); - - UNBLOCK_INPUT; - } - - /* Now that we have the pixmap, compute mask and transform the - image if requested. */ - BLOCK_INPUT; - postprocess_image (f, img); - UNBLOCK_INPUT; -} - -#endif /* HAVE_GHOSTSCRIPT */ /*********************************************************************** @@ -12468,12 +6774,25 @@ x_kill_gs_process (pixmap, f) ***********************************************************************/ DEFUN ("x-change-window-property", Fx_change_window_property, - Sx_change_window_property, 2, 3, 0, + Sx_change_window_property, 2, 6, 0, doc: /* Change window property PROP to VALUE on the X window of FRAME. -PROP and VALUE must be strings. FRAME nil or omitted means use the -selected frame. Value is VALUE. */) - (prop, value, frame) - Lisp_Object frame, prop, value; +VALUE may be a string or a list of conses, numbers and/or strings. +If an element in the list is a string, it is converted to +an Atom and the value of the Atom is used. If an element is a cons, +it is converted to a 32 bit number where the car is the 16 top bits and the +cdr is the lower 16 bits. +FRAME nil or omitted means use the selected frame. +If TYPE is given and non-nil, it is the name of the type of VALUE. +If TYPE is not given or nil, the type is STRING. +FORMAT gives the size in bits of each element if VALUE is a list. +It must be one of 8, 16 or 32. +If VALUE is a string or FORMAT is nil or not given, FORMAT defaults to 8. +If OUTER_P is non-nil, the property is changed for the outer X window of +FRAME. Default is to change on the edit X window. + +Value is VALUE. */) + (prop, value, frame, type, format, outer_p) + Lisp_Object prop, value, frame, type, format, outer_p; { #if 0 /* TODO : port window properties to W32 */ struct frame *f = check_x_frame (frame); @@ -13990,6 +8309,76 @@ If the underlying system call fails, value is nil. */) return value; } +DEFUN ("default-printer-name", Fdefault_printer_name, Sdefault_printer_name, + 0, 0, 0, doc: /* Return the name of Windows default printer device. */) + () +{ + static char pname_buf[256]; + int err; + HANDLE hPrn; + PRINTER_INFO_2 *ppi2 = NULL; + DWORD dwNeeded = 0, dwReturned = 0; + + /* Retrieve the default string from Win.ini (the registry). + * String will be in form "printername,drivername,portname". + * This is the most portable way to get the default printer. */ + if (GetProfileString ("windows", "device", ",,", pname_buf, sizeof (pname_buf)) <= 0) + return Qnil; + /* printername precedes first "," character */ + strtok (pname_buf, ","); + /* We want to know more than the printer name */ + if (!OpenPrinter (pname_buf, &hPrn, NULL)) + return Qnil; + GetPrinter (hPrn, 2, NULL, 0, &dwNeeded); + if (dwNeeded == 0) + { + ClosePrinter (hPrn); + return Qnil; + } + /* Allocate memory for the PRINTER_INFO_2 struct */ + ppi2 = (PRINTER_INFO_2 *) xmalloc (dwNeeded); + if (!ppi2) + { + ClosePrinter (hPrn); + return Qnil; + } + /* Call GetPrinter() again with big enouth memory block */ + err = GetPrinter (hPrn, 2, (LPBYTE)ppi2, dwNeeded, &dwReturned); + ClosePrinter (hPrn); + if (!err) + { + xfree(ppi2); + return Qnil; + } + + if (ppi2) + { + if (ppi2->Attributes & PRINTER_ATTRIBUTE_SHARED && ppi2->pServerName) + { + /* a remote printer */ + if (*ppi2->pServerName == '\\') + _snprintf(pname_buf, sizeof (pname_buf), "%s\\%s", ppi2->pServerName, + ppi2->pShareName); + else + _snprintf(pname_buf, sizeof (pname_buf), "\\\\%s\\%s", ppi2->pServerName, + ppi2->pShareName); + pname_buf[sizeof (pname_buf) - 1] = '\0'; + } + else + { + /* a local printer */ + strncpy(pname_buf, ppi2->pPortName, sizeof (pname_buf)); + pname_buf[sizeof (pname_buf) - 1] = '\0'; + /* `pPortName' can include several ports, delimited by ','. + * we only use the first one. */ + strtok(pname_buf, ","); + } + xfree(ppi2); + } + + return build_string (pname_buf); +} + /*********************************************************************** Initialization ***********************************************************************/ @@ -14046,8 +8435,6 @@ syms_of_w32fns () staticpro (&Qsuppress_icon); Qundefined_color = intern ("undefined-color"); staticpro (&Qundefined_color); - Qcenter = intern ("center"); - staticpro (&Qcenter); Qcancel_timer = intern ("cancel-timer"); staticpro (&Qcancel_timer); @@ -14072,21 +8459,6 @@ syms_of_w32fns () = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky); - Qlaplace = intern ("laplace"); - staticpro (&Qlaplace); - Qemboss = intern ("emboss"); - staticpro (&Qemboss); - Qedge_detection = intern ("edge-detection"); - staticpro (&Qedge_detection); - Qheuristic = intern ("heuristic"); - staticpro (&Qheuristic); - QCmatrix = intern (":matrix"); - staticpro (&QCmatrix); - QCcolor_adjustment = intern (":color-adjustment"); - staticpro (&QCcolor_adjustment); - QCmask = intern (":mask"); - staticpro (&QCmask); - Fput (Qundefined_color, Qerror_conditions, Fcons (Qundefined_color, Fcons (Qerror, Qnil))); Fput (Qundefined_color, Qerror_message, @@ -14217,10 +8589,6 @@ If this variable is non-nil, Emacs will pass them on, allowing the system to handle them. */); w32_pass_extra_mouse_buttons_to_system = 0; - DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path, - doc: /* List of directories to search for window system bitmap files. */); - Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH"); - DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape, doc: /* The shape of the pointer when over text. Changing the value does not affect existing frames @@ -14287,13 +8655,6 @@ such a font. This is especially effective for such large fonts as Chinese, Japanese, and Korean. */); Vx_pixel_size_width_font_regexp = Qnil; - DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay, - doc: /* Time after which cached images are removed from the cache. -When an image has not been displayed this many seconds, remove it -from the image cache. Value must be an integer or nil with nil -meaning don't clear the cache. */); - Vimage_cache_eviction_delay = make_number (30 * 60); - DEFVAR_LISP ("w32-bdf-filename-alist", &Vw32_bdf_filename_alist, doc: /* List of bdf fonts and their corresponding filenames. */); @@ -14442,6 +8803,7 @@ versions of Windows) characters. */); defsubr (&Sw32_find_bdf_fonts); defsubr (&Sfile_system_info); + defsubr (&Sdefault_printer_name); /* Setting callback functions for fontset handler. */ get_font_info_func = w32_get_font_info; @@ -14458,69 +8820,6 @@ versions of Windows) characters. */); get_font_repertory_func = x_get_font_repertory; check_window_system_func = check_w32; - /* Images. */ - Qxbm = intern ("xbm"); - staticpro (&Qxbm); - QCconversion = intern (":conversion"); - staticpro (&QCconversion); - QCheuristic_mask = intern (":heuristic-mask"); - staticpro (&QCheuristic_mask); - QCcolor_symbols = intern (":color-symbols"); - staticpro (&QCcolor_symbols); - QCascent = intern (":ascent"); - staticpro (&QCascent); - QCmargin = intern (":margin"); - staticpro (&QCmargin); - QCrelief = intern (":relief"); - staticpro (&QCrelief); - Qpostscript = intern ("postscript"); - staticpro (&Qpostscript); - QCloader = intern (":loader"); - staticpro (&QCloader); - QCbounding_box = intern (":bounding-box"); - staticpro (&QCbounding_box); - QCpt_width = intern (":pt-width"); - staticpro (&QCpt_width); - QCpt_height = intern (":pt-height"); - staticpro (&QCpt_height); - QCindex = intern (":index"); - staticpro (&QCindex); - Qpbm = intern ("pbm"); - staticpro (&Qpbm); - -#if HAVE_XPM - Qxpm = intern ("xpm"); - staticpro (&Qxpm); -#endif - -#if HAVE_JPEG - Qjpeg = intern ("jpeg"); - staticpro (&Qjpeg); -#endif - -#if HAVE_TIFF - Qtiff = intern ("tiff"); - staticpro (&Qtiff); -#endif - -#if HAVE_GIF - Qgif = intern ("gif"); - staticpro (&Qgif); -#endif - -#if HAVE_PNG - Qpng = intern ("png"); - staticpro (&Qpng); -#endif - - defsubr (&Sclear_image_cache); - defsubr (&Simage_size); - defsubr (&Simage_mask_p); - -#if GLYPH_DEBUG - defsubr (&Simagep); - defsubr (&Slookup_image); -#endif hourglass_atimer = NULL; hourglass_shown_p = 0; @@ -14560,84 +8859,6 @@ void globals_of_w32fns () GetProcAddress (user32_lib, "GetClipboardSequenceNumber"); } -/* Initialize image types. Based on which libraries are available. */ -static void -init_external_image_libraries () -{ - HINSTANCE library; - -#if HAVE_XPM - if ((library = LoadLibrary ("libXpm.dll"))) - { - if (init_xpm_functions (library)) - define_image_type (&xpm_type); - } - -#endif - -#if HAVE_JPEG - /* Try loading jpeg library under probable names. */ - if ((library = LoadLibrary ("libjpeg.dll")) - || (library = LoadLibrary ("jpeg-62.dll")) - || (library = LoadLibrary ("jpeg.dll"))) - { - if (init_jpeg_functions (library)) - define_image_type (&jpeg_type); - } -#endif - -#if HAVE_TIFF - if (library = LoadLibrary ("libtiff.dll")) - { - if (init_tiff_functions (library)) - define_image_type (&tiff_type); - } -#endif - -#if HAVE_GIF - if (library = LoadLibrary ("libungif.dll")) - { - if (init_gif_functions (library)) - define_image_type (&gif_type); - } -#endif - -#if HAVE_PNG - /* Ensure zlib is loaded. Try debug version first. */ - if (!LoadLibrary ("zlibd.dll")) - LoadLibrary ("zlib.dll"); - - /* Try loading libpng under probable names. */ - if ((library = LoadLibrary ("libpng13d.dll")) - || (library = LoadLibrary ("libpng13.dll")) - || (library = LoadLibrary ("libpng12d.dll")) - || (library = LoadLibrary ("libpng12.dll")) - || (library = LoadLibrary ("libpng.dll"))) - { - if (init_png_functions (library)) - define_image_type (&png_type); - } -#endif -} - -void -init_xfns () -{ - image_types = NULL; - Vimage_types = Qnil; - - define_image_type (&pbm_type); - define_image_type (&xbm_type); - -#if 0 /* TODO : Ghostscript support for W32 */ - define_image_type (&gs_type); -#endif - - /* Image types that rely on external libraries are loaded dynamically - if the library is available. */ - init_external_image_libraries (); -} - #undef abort void @@ -14670,3 +8891,6 @@ w32_last_error() { return GetLastError (); } + +/* arch-tag: 707589ab-b9be-4638-8cdd-74629cc9b446 + (do not change this comment) */ diff --git a/src/w32gui.h b/src/w32gui.h index 7aedfbc47ec..04182c6da80 100644 --- a/src/w32gui.h +++ b/src/w32gui.h @@ -176,3 +176,6 @@ typedef struct { #endif /* EMACS_W32GUI_H */ + +/* arch-tag: 9172e5fb-45a5-4684-afd9-ca0e81324604 + (do not change this comment) */ diff --git a/src/w32heap.c b/src/w32heap.c index 11ec7c1b6c6..b40db430ea9 100644 --- a/src/w32heap.c +++ b/src/w32heap.c @@ -304,3 +304,6 @@ _heap_term (void) } #endif + +/* arch-tag: 9a6a9860-040d-422d-8905-450dd535cd9c + (do not change this comment) */ diff --git a/src/w32heap.h b/src/w32heap.h index 6abd658b76d..7fdf952683c 100644 --- a/src/w32heap.h +++ b/src/w32heap.h @@ -103,3 +103,6 @@ IMAGE_SECTION_HEADER * find_section (char * name, IMAGE_NT_HEADERS * nt_header); IMAGE_SECTION_HEADER * rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header); #endif /* NTHEAP_H_ */ + +/* arch-tag: 3ba4cbe1-8a09-4a41-8f37-fd31f7426b3c + (do not change this comment) */ diff --git a/src/w32inevt.c b/src/w32inevt.c index f602f8b820b..168a0fb87b3 100644 --- a/src/w32inevt.c +++ b/src/w32inevt.c @@ -642,8 +642,7 @@ maybe_generate_resize_event () } int -w32_console_read_socket (int sd, struct input_event *bufp, int numchars, - int expected) +w32_console_read_socket (int sd, int expected, struct input_event *hold_quit) { BOOL no_events = TRUE; int nev, ret = 0, add; @@ -670,27 +669,31 @@ w32_console_read_socket (int sd, struct input_event *bufp, int numchars, return nev; } - while (nev > 0 && numchars > 0) + while (nev > 0) { + struct input_event inev; + + EVENT_INIT (inev); + inev.kind = NO_EVENT; + inev.arg = Qnil; + switch (queue_ptr->EventType) { case KEY_EVENT: - add = key_event (&queue_ptr->Event.KeyEvent, bufp, &isdead); + add = key_event (&queue_ptr->Event.KeyEvent, &inev, &isdead); if (add == -1) /* 95.7.25 by himi */ { queue_ptr--; add = 1; } - bufp += add; - ret += add; - numchars -= add; + if (add) + kbd_buffer_store_event_hold (&inev, hold_quit); break; case MOUSE_EVENT: - add = do_mouse_event (&queue_ptr->Event.MouseEvent, bufp); - bufp += add; - ret += add; - numchars -= add; + add = do_mouse_event (&queue_ptr->Event.MouseEvent, &inev); + if (add) + kbd_buffer_store_event_hold (&inev, hold_quit); break; case WINDOW_BUFFER_SIZE_EVENT: @@ -721,3 +724,6 @@ w32_console_read_socket (int sd, struct input_event *bufp, int numchars, UNBLOCK_INPUT; return ret; } + +/* arch-tag: 0bcb39b7-d085-4b85-9070-6750e8c03047 + (do not change this comment) */ diff --git a/src/w32inevt.h b/src/w32inevt.h index 7df989bffdc..fb61cb0ef55 100644 --- a/src/w32inevt.h +++ b/src/w32inevt.h @@ -21,8 +21,8 @@ Boston, MA 02111-1307, USA. */ #ifndef EMACS_W32INEVT_H #define EMACS_W32INEVT_H -extern int w32_console_read_socket (int sd, struct input_event *bufp, - int numchars, int expected); +extern int w32_console_read_socket (int sd, int numchars, + struct input_event *hold_quit); extern void w32_console_mouse_position (FRAME_PTR *f, int insist, Lisp_Object *bar_window, enum scroll_bar_part *part, @@ -30,3 +30,6 @@ extern void w32_console_mouse_position (FRAME_PTR *f, int insist, unsigned long *time); #endif /* EMACS_W32INEVT_H */ + +/* arch-tag: 7641bd54-199f-4552-8e8a-6a2f5340ef13 + (do not change this comment) */ diff --git a/src/w32menu.c b/src/w32menu.c index 02bd62eb160..5f8f8a4e5e0 100644 --- a/src/w32menu.c +++ b/src/w32menu.c @@ -153,7 +153,6 @@ Lisp_Object Vmenu_updating_frame; Lisp_Object Qdebug_on_next_call; extern Lisp_Object Qmenu_bar; -extern Lisp_Object Qmouse_click, Qevent_kind; extern Lisp_Object QCtoggle, QCradio; @@ -2416,3 +2415,6 @@ void globals_of_w32menu () get_menu_item_info = (GetMenuItemInfoA_Proc) GetProcAddress (user32, "GetMenuItemInfoA"); set_menu_item_info = (SetMenuItemInfoA_Proc) GetProcAddress (user32, "SetMenuItemInfoA"); } + +/* arch-tag: 0eaed431-bb4e-4aac-a527-95a1b4f1fed0 + (do not change this comment) */ diff --git a/src/w32proc.c b/src/w32proc.c index 7241784925c..edd286e50d0 100644 --- a/src/w32proc.c +++ b/src/w32proc.c @@ -2238,3 +2238,6 @@ are supported. Moreover, it slows down `file-attributes' noticeably. */); Vw32_get_true_file_attributes = Qt; } /* end of ntproc.c */ + +/* arch-tag: 23d3a34c-06d2-48a1-833b-ac7609aa5250 + (do not change this comment) */ diff --git a/src/w32reg.c b/src/w32reg.c index 6d3137f1d4f..97abbed5d2e 100644 --- a/src/w32reg.c +++ b/src/w32reg.c @@ -163,3 +163,6 @@ x_get_string_resource (rdb, name, class) return (w32_get_string_resource (name, class, REG_SZ)); } + +/* arch-tag: 755fce25-42d7-4acb-874f-2fb42336823d + (do not change this comment) */ diff --git a/src/w32select.c b/src/w32select.c index a9cae2a3fe4..21f828d1f0c 100644 --- a/src/w32select.c +++ b/src/w32select.c @@ -479,3 +479,6 @@ set to nil. */); QCLIPBOARD = intern ("CLIPBOARD"); staticpro (&QCLIPBOARD); } + +/* arch-tag: c96e9724-5eb1-4dad-be07-289f092fd2af + (do not change this comment) */ diff --git a/src/w32term.c b/src/w32term.c index 7dad401a13a..a9afc99b959 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -248,8 +248,6 @@ static int input_signal_count; extern Lisp_Object Vcommand_line_args, Vsystem_name; -extern Lisp_Object Qface, Qmouse_face; - #ifndef USE_CRT_DLL extern int errno; #endif @@ -569,6 +567,9 @@ x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p) output_cursor.x, output_cursor.y); x_draw_vertical_border (w); + + draw_window_fringes (w); + UNBLOCK_INPUT; } @@ -653,11 +654,7 @@ x_after_update_window_line (desired_row) xassert (w); if (!desired_row->mode_line_p && !w->pseudo_window_p) - { - BLOCK_INPUT; - draw_row_fringe_bitmaps (w, desired_row); - UNBLOCK_INPUT; - } + desired_row->redraw_fringe_bitmaps_p = 1; /* When a window has disappeared, make sure that no rest of full-width rows stays visible in the internal border. Could @@ -707,34 +704,79 @@ w32_draw_fringe_bitmap (w, row, p) struct frame *f = XFRAME (WINDOW_FRAME (w)); HDC hdc; struct face *face = p->face; + int rowY; hdc = get_frame_dc (f); /* Must clip because of partially visible lines. */ - w32_clip_to_row (w, row, hdc); + rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); + if (p->y < rowY) + { + /* Adjust position of "bottom aligned" bitmap on partially + visible last row. */ + int oldY = row->y; + int oldVH = row->visible_height; + row->visible_height = p->h; + row->y -= rowY - p->y; + w32_clip_to_row (w, row, hdc); + row->y = oldY; + row->visible_height = oldVH; + } + else + w32_clip_to_row (w, row, hdc); - if (p->bx >= 0) + if (p->bx >= 0 && !p->overlay_p) { w32_fill_area (f, hdc, face->background, p->bx, p->by, p->nx, p->ny); } - if (p->which != NO_FRINGE_BITMAP) + if (p->which) { HBITMAP pixmap = fringe_bmp[p->which]; HDC compat_hdc; HANDLE horig_obj; compat_hdc = CreateCompatibleDC (hdc); + SaveDC (hdc); horig_obj = SelectObject (compat_hdc, pixmap); - SetTextColor (hdc, face->background); - SetBkColor (hdc, face->foreground); - BitBlt (hdc, p->x, p->y, p->wd, p->h, - compat_hdc, 0, p->dh, - SRCCOPY); + /* Paint overlays transparently. */ + if (p->overlay_p) + { + HBRUSH h_brush, h_orig_brush; + + SetTextColor (hdc, BLACK_PIX_DEFAULT (f)); + SetBkColor (hdc, WHITE_PIX_DEFAULT (f)); + h_brush = CreateSolidBrush (face->foreground); + h_orig_brush = SelectObject (hdc, h_brush); + + BitBlt (hdc, p->x, p->y, p->wd, p->h, + compat_hdc, 0, p->dh, + DSTINVERT); + BitBlt (hdc, p->x, p->y, p->wd, p->h, + compat_hdc, 0, p->dh, + 0x2E064A); + BitBlt (hdc, p->x, p->y, p->wd, p->h, + compat_hdc, 0, p->dh, + DSTINVERT); + + SelectObject (hdc, h_orig_brush); + DeleteObject (h_brush); + } + else + { + SetTextColor (hdc, face->background); + SetBkColor (hdc, (p->cursor_p + ? f->output_data.w32->cursor_pixel + : face->foreground)); + + BitBlt (hdc, p->x, p->y, p->wd, p->h, + compat_hdc, 0, p->dh, + SRCCOPY); + } SelectObject (compat_hdc, horig_obj); DeleteDC (compat_hdc); @@ -746,6 +788,25 @@ w32_draw_fringe_bitmap (w, row, p) release_frame_dc (f, hdc); } +static void +w32_define_fringe_bitmap (which, bits, h, wd) + int which; + unsigned short *bits; + int h, wd; +{ + fringe_bmp[which] = CreateBitmap (wd, h, 1, 1, bits); +} + +static void +w32_destroy_fringe_bitmap (which) + int which; +{ + if (fringe_bmp[which]) + DeleteObject (fringe_bmp[which]); + fringe_bmp[which] = 0; +} + + /* This is called when starting Emacs and when restarting after suspend. When starting Emacs, no window is mapped. And nothing @@ -1274,9 +1335,9 @@ w32_text_out (s, x, y,chars,nchars) wchar_t * chars; int nchars; { - int charset_dim = w32_font_is_double_byte (s->gc->font) ? 2 : 1; - if (s->gc->font->bdf) - w32_BDF_TextOut (s->gc->font->bdf, s->hdc, + int charset_dim = w32_font_is_double_byte (s->font) ? 2 : 1; + if (s->font->bdf) + w32_BDF_TextOut (s->font->bdf, s->hdc, x, y, (char *) chars, charset_dim, nchars * charset_dim, 0); else if (s->first_glyph->font_type == UNICODE_FONT) @@ -4212,8 +4273,6 @@ static short temp_buffer[100]; This routine is called by the SIGIO handler. We return as soon as there are no more events to be read. - Events representing keys are stored in buffer BUFP, - which can hold up to NUMCHARS characters. We return the number of characters stored into the buffer, thus pretending to be `read'. @@ -4229,11 +4288,10 @@ static short temp_buffer[100]; */ int -w32_read_socket (sd, bufp, numchars, expected) +w32_read_socket (sd, expected, hold_quit) register int sd; - /* register */ struct input_event *bufp; - /* register */ int numchars; int expected; + struct input_event *hold_quit; { int count = 0; int check_visibility = 0; @@ -4253,13 +4311,17 @@ w32_read_socket (sd, bufp, numchars, expected) /* So people can tell when we have read the available input. */ input_signal_count++; - if (numchars <= 0) - abort (); /* Don't think this happens. */ - /* TODO: tool-bars, ghostscript integration, mouse cursors. */ while (get_next_msg (&msg, FALSE)) { + struct input_event inev; + int do_help = 0; + + EVENT_INIT (inev); + inev.kind = NO_EVENT; + inev.arg = Qnil; + switch (msg.msg.message) { case WM_PAINT: @@ -4288,12 +4350,8 @@ w32_read_socket (sd, bufp, numchars, expected) visibility changes properly. */ if (f->iconified) { - bufp->kind = DEICONIFY_EVENT; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp++; - count++; - numchars--; + inev.kind = DEICONIFY_EVENT; + XSETFRAME (inev.frame_or_window, f); } else if (! NILP (Vframe_list) && ! NILP (XCDR (Vframe_list))) @@ -4323,17 +4381,10 @@ w32_read_socket (sd, bufp, numchars, expected) if (f) { - if (numchars == 0) - abort (); - - bufp->kind = LANGUAGE_CHANGE_EVENT; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp->code = msg.msg.wParam; - bufp->modifiers = msg.msg.lParam & 0xffff; - bufp++; - count++; - numchars--; + inev.kind = LANGUAGE_CHANGE_EVENT; + XSETFRAME (inev.frame_or_window, f); + inev.code = msg.msg.wParam; + inev.modifiers = msg.msg.lParam & 0xffff; } break; @@ -4345,22 +4396,18 @@ w32_read_socket (sd, bufp, numchars, expected) { if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)) { - dpyinfo->mouse_face_hidden = 1; clear_mouse_face (dpyinfo); + dpyinfo->mouse_face_hidden = 1; } if (temp_index == sizeof temp_buffer / sizeof (short)) temp_index = 0; temp_buffer[temp_index++] = msg.msg.wParam; - bufp->kind = NON_ASCII_KEYSTROKE_EVENT; - bufp->code = msg.msg.wParam; - bufp->modifiers = msg.dwModifiers; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp->timestamp = msg.msg.time; - bufp++; - numchars--; - count++; + inev.kind = NON_ASCII_KEYSTROKE_EVENT; + inev.code = msg.msg.wParam; + inev.modifiers = msg.dwModifiers; + XSETFRAME (inev.frame_or_window, f); + inev.timestamp = msg.msg.time; } break; @@ -4372,22 +4419,18 @@ w32_read_socket (sd, bufp, numchars, expected) { if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)) { - dpyinfo->mouse_face_hidden = 1; clear_mouse_face (dpyinfo); + dpyinfo->mouse_face_hidden = 1; } if (temp_index == sizeof temp_buffer / sizeof (short)) temp_index = 0; temp_buffer[temp_index++] = msg.msg.wParam; - bufp->kind = ASCII_KEYSTROKE_EVENT; - bufp->code = msg.msg.wParam; - bufp->modifiers = msg.dwModifiers; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp->timestamp = msg.msg.time; - bufp++; - numchars--; - count++; + inev.kind = ASCII_KEYSTROKE_EVENT; + inev.code = msg.msg.wParam; + inev.modifiers = msg.dwModifiers; + XSETFRAME (inev.frame_or_window, f); + inev.timestamp = msg.msg.time; } break; @@ -4433,13 +4476,10 @@ w32_read_socket (sd, bufp, numchars, expected) iff it is active. */ if (WINDOWP(window) && !EQ (window, last_window) - && !EQ (window, selected_window) - && numchars > 0) + && !EQ (window, selected_window)) { - bufp->kind = SELECT_WINDOW_EVENT; - bufp->frame_or_window = window; - bufp->arg = Qnil; - ++bufp, ++count, --numchars; + inev.kind = SELECT_WINDOW_EVENT; + inev.frame_or_window = window; } last_window=window; @@ -4457,27 +4497,8 @@ w32_read_socket (sd, bufp, numchars, expected) has changed, generate a HELP_EVENT. */ if (help_echo_string != previous_help_echo_string || (!NILP (help_echo_string) && !STRINGP (help_echo_string) && f->mouse_moved)) - { - Lisp_Object frame; - int n; + do_help = 1; - if (help_echo_string == Qnil) - { - help_echo_object = help_echo_window = Qnil; - help_echo_pos = -1; - } - - if (f) - XSETFRAME (frame, f); - else - frame = Qnil; - - any_help_event_p = 1; - n = gen_help_event (bufp, numchars, help_echo_string, frame, - help_echo_window, help_echo_object, - help_echo_pos); - bufp += n, count += n, numchars -= n; - } break; case WM_LBUTTONDOWN: @@ -4491,13 +4512,10 @@ w32_read_socket (sd, bufp, numchars, expected) { /* If we decide we want to generate an event to be seen by the rest of Emacs, we put it here. */ - struct input_event emacs_event; int tool_bar_p = 0; int button; int up; - emacs_event.kind = NO_EVENT; - if (dpyinfo->grabbed && last_mouse_frame && FRAME_LIVE_P (last_mouse_frame)) f = last_mouse_frame; @@ -4506,35 +4524,29 @@ w32_read_socket (sd, bufp, numchars, expected) if (f) { - construct_mouse_click (&emacs_event, &msg, f); + construct_mouse_click (&inev, &msg, f); /* Is this in the tool-bar? */ if (WINDOWP (f->tool_bar_window) && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window))) { Lisp_Object window; - int x = XFASTINT (emacs_event.x); - int y = XFASTINT (emacs_event.y); + int x = XFASTINT (inev.x); + int y = XFASTINT (inev.y); window = window_from_coordinates (f, x, y, 0, 0, 0, 1); if (EQ (window, f->tool_bar_window)) { - w32_handle_tool_bar_click (f, &emacs_event); + w32_handle_tool_bar_click (f, &inev); tool_bar_p = 1; } } - if (!tool_bar_p) - if (!dpyinfo->w32_focus_frame - || f == dpyinfo->w32_focus_frame - && (numchars >= 1)) - { - construct_mouse_click (bufp, &msg, f); - bufp++; - count++; - numchars--; - } + if (tool_bar_p + || (dpyinfo->w32_focus_frame + && f != dpyinfo->w32_focus_frame)) + inev.kind = NO_EVENT; } parse_button (msg.msg.message, HIWORD (msg.msg.wParam), @@ -4572,15 +4584,11 @@ w32_read_socket (sd, bufp, numchars, expected) if (f) { - if ((!dpyinfo->w32_focus_frame - || f == dpyinfo->w32_focus_frame) - && (numchars >= 1)) + if (!dpyinfo->w32_focus_frame + || f == dpyinfo->w32_focus_frame) { /* Emit an Emacs wheel-up/down event. */ - construct_mouse_wheel (bufp, &msg, f); - bufp++; - count++; - numchars--; + construct_mouse_wheel (&inev, &msg, f); } /* Ignore any mouse motion that happened before this event; any subsequent mouse-movement Emacs events @@ -4597,12 +4605,7 @@ w32_read_socket (sd, bufp, numchars, expected) f = x_window_to_frame (dpyinfo, msg.msg.hwnd); if (f) - { - construct_drag_n_drop (bufp, &msg, f); - bufp++; - count++; - numchars--; - } + construct_drag_n_drop (&inev, &msg, f); break; case WM_VSCROLL: @@ -4610,15 +4613,8 @@ w32_read_socket (sd, bufp, numchars, expected) struct scroll_bar *bar = x_window_to_scroll_bar ((HWND)msg.msg.lParam); - if (bar && numchars >= 1) - { - if (w32_scroll_bar_handle_click (bar, &msg, bufp)) - { - bufp++; - count++; - numchars--; - } - } + if (bar) + w32_scroll_bar_handle_click (bar, &msg, &inev); break; } @@ -4694,12 +4690,8 @@ w32_read_socket (sd, bufp, numchars, expected) f->async_visible = 0; f->async_iconified = 1; - bufp->kind = ICONIFY_EVENT; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp++; - count++; - numchars--; + inev.kind = ICONIFY_EVENT; + XSETFRAME (inev.frame_or_window, f); break; case SIZE_MAXIMIZED: @@ -4724,12 +4716,8 @@ w32_read_socket (sd, bufp, numchars, expected) f->left_pos = x; f->top_pos = y; - bufp->kind = DEICONIFY_EVENT; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp++; - count++; - numchars--; + inev.kind = DEICONIFY_EVENT; + XSETFRAME (inev.frame_or_window, f); } else if (! NILP (Vframe_list) && ! NILP (XCDR (Vframe_list))) @@ -4797,16 +4785,7 @@ w32_read_socket (sd, bufp, numchars, expected) Otherwise, the startup message is cleared when the mouse leaves the frame. */ if (any_help_event_p) - { - Lisp_Object frame; - int n; - - XSETFRAME (frame, f); - help_echo_string = Qnil; - n = gen_help_event (bufp, numchars, - Qnil, frame, Qnil, Qnil, 0); - bufp += n, count += n, numchars -= n; - } + do_help = -1; } break; @@ -4856,16 +4835,7 @@ w32_read_socket (sd, bufp, numchars, expected) Otherwise, the startup message is cleared when the mouse leaves the frame. */ if (any_help_event_p) - { - Lisp_Object frame; - int n; - - XSETFRAME (frame, f); - help_echo_string = Qnil; - n = gen_help_event (bufp, numchars, - Qnil, frame, Qnil, Qnil, 0); - bufp += n, count += n, numchars -=n; - } + do_help = -1; } dpyinfo->grabbed = 0; @@ -4877,15 +4847,8 @@ w32_read_socket (sd, bufp, numchars, expected) if (f) { - if (numchars == 0) - abort (); - - bufp->kind = DELETE_WINDOW_EVENT; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp++; - count++; - numchars--; + inev.kind = DELETE_WINDOW_EVENT; + XSETFRAME (inev.frame_or_window, f); } break; @@ -4894,15 +4857,8 @@ w32_read_socket (sd, bufp, numchars, expected) if (f) { - if (numchars == 0) - abort (); - - bufp->kind = MENU_BAR_ACTIVATE_EVENT; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp++; - count++; - numchars--; + inev.kind = MENU_BAR_ACTIVATE_EVENT; + XSETFRAME (inev.frame_or_window, f); } break; @@ -4944,6 +4900,42 @@ w32_read_socket (sd, bufp, numchars, expected) } break; } + + if (inev.kind != NO_EVENT) + { + kbd_buffer_store_event_hold (&inev, hold_quit); + count++; + } + + if (do_help + && !(hold_quit && hold_quit->kind != NO_EVENT)) + { + Lisp_Object frame; + + if (f) + XSETFRAME (frame, f); + else + frame = Qnil; + + if (do_help > 0) + { + if (help_echo_string == Qnil) + { + help_echo_object = help_echo_window = Qnil; + help_echo_pos = -1; + } + + any_help_event_p = 1; + gen_help_event (help_echo_string, frame, help_echo_window, + help_echo_object, help_echo_pos); + } + else + { + help_echo_string = Qnil; + gen_help_event (Qnil, frame, Qnil, Qnil, 0); + } + count++; + } } /* If the focus was just given to an autoraising frame, @@ -5235,6 +5227,9 @@ w32_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, act cursor remains invisible. */ if (w32_use_visible_system_caret) { + /* Call to erase_phys_cursor here seems to use the + wrong values of w->phys_cursor, as they have been + overwritten before this function was called. */ if (w->phys_cursor_type != NO_CURSOR) erase_phys_cursor (w); @@ -5274,6 +5269,14 @@ w32_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, act PostMessage (hwnd, WM_EMACS_TRACK_CARET, 0, 0); } + if (glyph_row->exact_window_width_line_p + && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA]) + { + glyph_row->cursor_in_fringe_p = 1; + draw_fringe_bitmap (w, glyph_row, 0); + return; + } + switch (cursor_type) { case HOLLOW_BOX_CURSOR: @@ -6369,32 +6372,7 @@ w32_term_init (display_name, xrm_option, resource_name) horizontally reflected compared to how they appear on X, so we need to bitswap and convert to unsigned shorts before creating the bitmaps. */ - { - int i, j; - - for (i = NO_FRINGE_BITMAP + 1; i < MAX_FRINGE_BITMAPS; i++) - { - int h = fringe_bitmaps[i].height; - int wd = fringe_bitmaps[i].width; - unsigned short *w32bits - = (unsigned short *)alloca (h * sizeof (unsigned short)); - unsigned short *wb = w32bits; - unsigned char *bits = fringe_bitmaps[i].bits; - for (j = 0; j < h; j++) - { - static unsigned char swap_nibble[16] - = { 0x0, 0x8, 0x4, 0xc, /* 0000 1000 0100 1100 */ - 0x2, 0xa, 0x6, 0xe, /* 0010 1010 0110 1110 */ - 0x1, 0x9, 0x5, 0xd, /* 0001 1001 0101 1101 */ - 0x3, 0xb, 0x7, 0xf }; /* 0011 1011 0111 1111 */ - - unsigned char b = *bits++; - *wb++ = (unsigned short)((swap_nibble[b & 0xf]<<4) - | (swap_nibble[(b>>4) & 0xf])); - } - fringe_bmp[i] = CreateBitmap (wd, h, 1, 1, w32bits); - } - } + w32_init_fringe (); #ifndef F_SETOWN_BUG #ifdef F_SETOWN @@ -6462,13 +6440,7 @@ x_delete_display (dpyinfo) xfree (dpyinfo->font_table); xfree (dpyinfo->w32_id_name); - /* Destroy row bitmaps. */ - { - int i; - - for (i = NO_FRINGE_BITMAP + 1; i < MAX_FRINGE_BITMAPS; i++) - DeleteObject (fringe_bmp[i]); - } + w32_reset_fringes (); } /* Set up use of W32. */ @@ -6499,6 +6471,8 @@ static struct redisplay_interface w32_redisplay_interface = w32_get_glyph_overhangs, x_fix_overlapping_area, w32_draw_fringe_bitmap, + w32_define_fringe_bitmap, + w32_destroy_fringe_bitmap, w32_per_char_metric, w32_encode_char, NULL, /* w32_compute_glyph_string_overhangs */ @@ -6696,3 +6670,6 @@ the cursor have no effect. */); staticpro (&last_mouse_motion_frame); last_mouse_motion_frame = Qnil; } + +/* arch-tag: 5fa70624-ab86-499c-8a85-473958ee4646 + (do not change this comment) */ diff --git a/src/w32term.h b/src/w32term.h index 269ebf03f0a..cf6956c1efa 100644 --- a/src/w32term.h +++ b/src/w32term.h @@ -735,3 +735,6 @@ int image_ascent P_ ((struct image *, struct face *)); ? BDF_1D_FONT : BDF_2D_FONT)) typedef DWORD (WINAPI * ClipboardSequence_Proc) (); + +/* arch-tag: f201d05a-1240-4fc5-8ea4-ca24d4ee5671 + (do not change this comment) */ diff --git a/src/w32xfns.c b/src/w32xfns.c index 887320aa746..9f9a64558f6 100644 --- a/src/w32xfns.c +++ b/src/w32xfns.c @@ -409,3 +409,6 @@ x_sync (f) void *f; { } + +/* arch-tag: 4fab3695-4ad3-4cc6-a2b1-fd2c67dc46be + (do not change this comment) */ diff --git a/src/widget.c b/src/widget.c index eaf8e66e9a9..dbf55a34d9c 100644 --- a/src/widget.c +++ b/src/widget.c @@ -1016,3 +1016,6 @@ widget_store_internal_border (widget) ew->emacs_frame.internal_border_width = f->internal_border_width; } + +/* arch-tag: 931d28e5-0d59-405a-8325-7d475d0a13d9 + (do not change this comment) */ diff --git a/src/widget.h b/src/widget.h index f941d8648b2..c5d4f597ea3 100644 --- a/src/widget.h +++ b/src/widget.h @@ -99,3 +99,6 @@ void EmacsFrameSetCharSize P_ ((Widget, int, int)); void widget_store_internal_border P_ ((Widget widget)); #endif /* _EmacsFrame_h */ + +/* arch-tag: 98be17cc-8878-4701-abfa-66f1c04e9cb7 + (do not change this comment) */ diff --git a/src/widgetprv.h b/src/widgetprv.h index d7bec41289c..b75ef769029 100644 --- a/src/widgetprv.h +++ b/src/widgetprv.h @@ -77,3 +77,6 @@ extern EmacsFrameClassRec emacsFrameClassRec; /* class pointer */ #endif /* _EmacsFrameP_h */ + +/* arch-tag: 2b579b4c-f697-4f86-b27a-35b7cb1a4a1c + (do not change this comment) */ diff --git a/src/window.c b/src/window.c index fd35ac8a9d8..47bbf0806ee 100644 --- a/src/window.c +++ b/src/window.c @@ -279,6 +279,7 @@ make_window () p->fringes_outside_margins = Qnil; p->scroll_bar_width = Qnil; p->vertical_scroll_bar_type = Qt; + p->overlay_arrow_bitmap = 0; Vwindow_list = Qnil; return val; @@ -305,7 +306,8 @@ used by that frame. */) } DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 0, 1, 0, - doc: /* Returns non-nil if WINDOW is a minibuffer window. */) + doc: /* Returns non-nil if WINDOW is a minibuffer window. +WINDOW defaults to the selected window. */) (window) Lisp_Object window; { @@ -392,6 +394,17 @@ decode_window (window) return XWINDOW (window); } +static struct window * +decode_any_window (window) + register Lisp_Object window; +{ + if (NILP (window)) + return XWINDOW (selected_window); + + CHECK_WINDOW (window); + return XWINDOW (window); +} + DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0, doc: /* Return the buffer that WINDOW is displaying. */) (window) @@ -405,7 +418,7 @@ DEFUN ("window-height", Fwindow_height, Swindow_height, 0, 1, 0, (window) Lisp_Object window; { - return decode_window (window)->total_lines; + return decode_any_window (window)->total_lines; } DEFUN ("window-width", Fwindow_width, Swindow_width, 0, 1, 0, @@ -416,7 +429,7 @@ use (let ((edges (window-edges))) (- (nth 2 edges) (nth 0 edges))). */) (window) Lisp_Object window; { - return make_number (window_box_text_cols (decode_window (window))); + return make_number (window_box_text_cols (decode_any_window (window))); } DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0, @@ -489,7 +502,7 @@ To get the edges of the actual text area, use `window-inside-edges'. */) (window) Lisp_Object window; { - register struct window *w = decode_window (window); + register struct window *w = decode_any_window (window); return Fcons (make_number (WINDOW_LEFT_EDGE_COL (w)), Fcons (make_number (WINDOW_TOP_EDGE_LINE (w)), @@ -509,7 +522,7 @@ To get the edges of the actual text area, use `window-inside-pixel-edges'. */) (window) Lisp_Object window; { - register struct window *w = decode_window (window); + register struct window *w = decode_any_window (window); return Fcons (make_number (WINDOW_LEFT_EDGE_X (w)), Fcons (make_number (WINDOW_TOP_EDGE_Y (w)), @@ -528,7 +541,7 @@ display margins, fringes, header line, and/or mode line. */) (window) Lisp_Object window; { - register struct window *w = decode_window (window); + register struct window *w = decode_any_window (window); return list4 (make_number (WINDOW_BOX_LEFT_EDGE_COL (w) + WINDOW_LEFT_MARGIN_COLS (w) @@ -552,7 +565,7 @@ display margins, fringes, header line, and/or mode line. */) (window) Lisp_Object window; { - register struct window *w = decode_window (window); + register struct window *w = decode_any_window (window); return list4 (make_number (WINDOW_BOX_LEFT_EDGE_X (w) + WINDOW_LEFT_MARGIN_WIDTH (w) @@ -632,8 +645,7 @@ coordinates_in_window (w, x, y) scroll bars. */ if (WINDOW_WANTS_MODELINE_P (w) - && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w) - && *y < bottom_y) + && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w)) { part = ON_MODE_LINE; @@ -662,7 +674,6 @@ coordinates_in_window (w, x, y) } if (WINDOW_WANTS_HEADER_LINE_P (w) - && *y >= top_y && *y < top_y + CURRENT_HEADER_LINE_HEIGHT (w)) { part = ON_HEADER_LINE; @@ -708,7 +719,7 @@ coordinates_in_window (w, x, y) ? (*x >= left_x + WINDOW_LEFT_FRINGE_WIDTH (w)) : (*x < left_x + lmargin_width))) { - *x -= x0; + *x -= left_x; if (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)) *x -= WINDOW_LEFT_FRINGE_WIDTH (w); *y -= top_y; @@ -773,7 +784,7 @@ If they are in the windows's left or right marginal areas, `left-margin'\n\ int x, y; Lisp_Object lx, ly; - CHECK_LIVE_WINDOW (window); + CHECK_WINDOW (window); w = XWINDOW (window); f = XFRAME (w->frame); CHECK_CONS (coordinates); @@ -1831,6 +1842,7 @@ enum window_loop DELETE_BUFFER_WINDOWS, /* Arg is buffer */ GET_LARGEST_WINDOW, UNSHOW_BUFFER, /* Arg is buffer */ + REDISPLAY_BUFFER_WINDOWS, /* Arg is buffer */ CHECK_ALL_WINDOWS }; @@ -2029,6 +2041,17 @@ window_loop (type, obj, mini, frames) } break; + case REDISPLAY_BUFFER_WINDOWS: + if (EQ (w->buffer, obj)) + { + mark_window_display_accurate (window, 0); + w->update_mode_line = Qt; + XBUFFER (obj)->prevent_redisplay_optimizations_p = 1; + ++update_mode_lines; + best_window = window; + } + break; + /* Check for a window that has a killed buffer. */ case CHECK_ALL_WINDOWS: if (! NILP (w->buffer) @@ -2055,6 +2078,7 @@ check_all_windows () DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0, doc: /* Return the window least recently selected or used for display. +Return a full-width window if possible. If optional argument FRAME is `visible', search all visible frames. If FRAME is 0, search all visible and iconified frames. If FRAME is t, search all frames. @@ -2538,6 +2562,118 @@ adjust_window_margins (w) return 1; } +/* Calculate new sizes for windows in the list FORWARD when the window size + goes from TOTAL to SIZE. TOTAL must be greater than SIZE. + The number of windows in FORWARD is NCHILDREN, and the number that + can shrink is SHRINKABLE. + The minimum size a window can have is MIN_SIZE. + If we are shrinking fixed windows, RESIZE_FIXED_P is non-zero. + If we are shrinking columns, WIDTH_P is non-zero, otherwise we are + shrinking rows. + + This function returns an allocated array of new sizes that the caller + must free. The size -1 means the window is fixed and RESIZE_FIXED_P + is zero. Array index 0 refers to the first window in FORWARD, 1 to + the second, and so on. + + This function tries to keep windows at least at the minimum size + and resize other windows before it resizes any window to zero (i.e. + delete that window). + + Windows are resized proportional to their size, so bigger windows + shrink more than smaller windows. */ +static int * +shrink_windows (total, size, nchildren, shrinkable, + min_size, resize_fixed_p, forward, width_p) + int total, size, nchildren, shrinkable, min_size; + int resize_fixed_p, width_p; + Lisp_Object forward; +{ + int available_resize = 0; + int *new_sizes; + struct window *c; + Lisp_Object child; + int smallest = total; + int total_removed = 0; + int total_shrink = total - size; + int i; + + new_sizes = xmalloc (sizeof (*new_sizes) * nchildren); + + for (i = 0, child = forward; !NILP (child); child = c->next, ++i) + { + int child_size; + + c = XWINDOW (child); + child_size = width_p ? XINT (c->total_cols) : XINT (c->total_lines); + + if (! resize_fixed_p && window_fixed_size_p (c, width_p, 0)) + new_sizes[i] = -1; + else + { + new_sizes[i] = child_size; + if (child_size > min_size) + available_resize += child_size - min_size; + } + } + /* We might need to shrink some windows to zero. Find the smallest + windows and set them to 0 until we can fulfil the new size. */ + + while (shrinkable > 1 && size + available_resize < total) + { + for (i = 0; i < nchildren; ++i) + if (new_sizes[i] > 0 && smallest > new_sizes[i]) + smallest = new_sizes[i]; + + for (i = 0; i < nchildren; ++i) + if (new_sizes[i] == smallest) + { + /* Resize this window down to zero. */ + new_sizes[i] = 0; + if (smallest > min_size) + available_resize -= smallest - min_size; + available_resize += smallest; + --shrinkable; + total_removed += smallest; + + /* Out of for, just remove one window at the time and + check again if we have enough space. */ + break; + } + } + + /* Now, calculate the new sizes. Try to shrink each window + proportional to its size. */ + for (i = 0; i < nchildren; ++i) + { + if (new_sizes[i] > min_size) + { + int to_shrink = total_shrink*new_sizes[i]/total; + if (new_sizes[i] - to_shrink < min_size) + to_shrink = new_sizes[i] - min_size; + new_sizes[i] -= to_shrink; + total_removed += to_shrink; + } + } + + /* Any reminder due to rounding, we just subtract from windows + that are left and still can be shrunk. */ + while (total_shrink > total_removed) + { + for (i = 0; i < nchildren; ++i) + if (new_sizes[i] > min_size) + { + --new_sizes[i]; + ++total_removed; + + /* Out of for, just shrink one window at the time and + check again if we have enough space. */ + break; + } + } + + return new_sizes; +} /* Set WINDOW's height or width to SIZE. WIDTH_P non-zero means set WINDOW's width. Resize WINDOW's children, if any, so that they @@ -2641,6 +2777,7 @@ size_window (window, size, width_p, nodelete_p) int fixed_size, each, extra, n; int resize_fixed_p, nfixed; int last_pos, first_pos, nchildren, total; + int *new_sizes = NULL; /* Determine the fixed-size portion of the this window, and the number of child windows. */ @@ -2665,16 +2802,22 @@ size_window (window, size, width_p, nodelete_p) windows. */ resize_fixed_p = nfixed == nchildren || size < fixed_size; - /* Compute how many lines/columns to add to each child. The + /* Compute how many lines/columns to add/remove to each child. The value of extra takes care of rounding errors. */ n = resize_fixed_p ? nchildren : nchildren - nfixed; - each = (size - total) / n; - extra = (size - total) - n * each; + if (size < total && n > 1) + new_sizes = shrink_windows (total, size, nchildren, n, min_size, + resize_fixed_p, *forward, width_p); + else + { + each = (size - total) / n; + extra = (size - total) - n * each; + } /* Compute new children heights and edge positions. */ first_pos = width_p ? XINT (w->left_col) : XINT (w->top_line); last_pos = first_pos; - for (child = *forward; !NILP (child); child = c->next) + for (n = 0, child = *forward; !NILP (child); child = c->next, ++n) { int new_size, old_size; @@ -2692,7 +2835,7 @@ size_window (window, size, width_p, nodelete_p) /* If this child can be resized, do it. */ if (resize_fixed_p || !window_fixed_size_p (c, width_p, 0)) { - new_size = old_size + each + extra; + new_size = new_sizes ? new_sizes[n] : old_size + each + extra; extra = 0; } @@ -2703,9 +2846,11 @@ size_window (window, size, width_p, nodelete_p) /* Remember the bottom/right edge position of this child; it will be used to set the top/left edge of the next child. */ - last_pos += new_size; + last_pos += new_size; } + if (new_sizes) xfree (new_sizes); + /* We should have covered the parent exactly with child windows. */ xassert (size == last_pos - first_pos); @@ -2853,6 +2998,9 @@ set_window_buffer (window, buffer, run_hooks_p, keep_margins_p) /* This may call adjust_window_margins three times, so temporarily disable window margins. */ + Lisp_Object save_left = w->left_margin_cols; + Lisp_Object save_right = w->right_margin_cols; + w->left_margin_cols = w->right_margin_cols = Qnil; Fset_window_fringes (window, @@ -2863,6 +3011,9 @@ set_window_buffer (window, buffer, run_hooks_p, keep_margins_p) b->scroll_bar_width, b->vertical_scroll_bar_type, Qnil); + w->left_margin_cols = save_left; + w->right_margin_cols = save_right; + Fset_window_margins (window, b->left_margin_cols, b->right_margin_cols); } @@ -3118,9 +3269,10 @@ Returns the window displaying BUFFER. If `display-buffer-reuse-frames' is non-nil, and another frame is currently displaying BUFFER, then simply raise that frame. -The variables `special-display-buffer-names', `special-display-regexps', -`same-window-buffer-names', and `same-window-regexps' customize how certain -buffer names are handled. +The variables `special-display-buffer-names', +`special-display-regexps', `same-window-buffer-names', and +`same-window-regexps' customize how certain buffer names are handled. +The latter two take effect only if NOT-THIS-WINDOW is t. If optional argument FRAME is `visible', search all visible frames. If FRAME is 0, search all visible and iconified frames. @@ -3303,6 +3455,52 @@ displayed. */) return display_buffer_1 (window); } + +DEFUN ("force-window-update", Fforce_window_update, Sforce_window_update, + 0, 1, 0, + doc: /* Force redisplay of all windows. +If optional arg OBJECT is a window, force redisplay of that window only. +If OBJECT is a buffer or buffer name, force redisplay of all windows +displaying that buffer. */) + (object) + Lisp_Object object; +{ + if (NILP (object)) + { + windows_or_buffers_changed++; + update_mode_lines++; + return Qt; + } + + if (WINDOWP (object)) + { + struct window *w = XWINDOW (object); + mark_window_display_accurate (object, 0); + w->update_mode_line = Qt; + if (BUFFERP (w->buffer)) + XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1; + ++update_mode_lines; + return Qt; + } + + if (STRINGP (object)) + object = Fget_buffer (object); + if (BUFFERP (object) && !NILP (XBUFFER (object)->name)) + { + /* Walk all windows looking for buffer, and force update + of each of those windows. */ + + object = window_loop (REDISPLAY_BUFFER_WINDOWS, object, 0, Qvisible); + return NILP (object) ? Qnil : Qt; + } + + /* If nothing suitable was found, just return. + We could signal an error, but this feature will typically be used + asynchronously in timers or process sentinels, so we don't. */ + return Qnil; +} + + void temp_output_buffer_show (buf) register Lisp_Object buf; @@ -5719,38 +5917,32 @@ usage: (save-window-excursion BODY ...) */) DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins, 2, 3, 0, doc: /* Set width of marginal areas of window WINDOW. -If window is nil, set margins of the currently selected window. -First parameter LEFT-WIDTH specifies the number of character -cells to reserve for the left marginal area. Second parameter -RIGHT-WIDTH does the same for the right marginal area. -A nil width parameter means no margin. */) +If WINDOW is nil, set margins of the currently selected window. +Second arg LEFT-WIDTH specifies the number of character cells to +reserve for the left marginal area. Optional third arg RIGHT-WIDTH +does the same for the right marginal area. A nil width parameter +means no margin. */) (window, left, right) Lisp_Object window, left, right; { struct window *w = decode_window (window); - /* TODO: It doesn't make sense to use FLOATs here, since - the rest of the code assumes they are integers. - So don't allow floats! ++KFS */ + /* Translate negative or zero widths to nil. + Margins that are too wide have to be checked elsewhere. */ if (!NILP (left)) - CHECK_NUMBER_OR_FLOAT (left); - if (!NILP (right)) - CHECK_NUMBER_OR_FLOAT (right); + { + CHECK_NUMBER (left); + if (XINT (left) <= 0) + left = Qnil; + } - /* Check widths < 0 and translate a zero width to nil. - Margins that are too wide have to be checked elsewhere. */ - if ((INTEGERP (left) && XINT (left) < 0) - || (FLOATP (left) && XFLOAT_DATA (left) <= 0)) - XSETFASTINT (left, 0); - if (INTEGERP (left) && XFASTINT (left) == 0) - left = Qnil; - - if ((INTEGERP (right) && XINT (right) < 0) - || (FLOATP (right) && XFLOAT_DATA (right) <= 0)) - XSETFASTINT (right, 0); - if (INTEGERP (right) && XFASTINT (right) == 0) - right = Qnil; + if (!NILP (right)) + { + CHECK_NUMBER (right); + if (XINT (right) <= 0) + right = Qnil; + } if (!EQ (w->left_margin_cols, left) || !EQ (w->right_margin_cols, right)) @@ -5790,15 +5982,17 @@ as nil. */) DEFUN ("set-window-fringes", Fset_window_fringes, Sset_window_fringes, 2, 4, 0, - doc: /* Set width of fringes of window WINDOW. - -If window is nil, set fringes of the currently selected window. -Second parameter LEFT-WIDTH specifies the number of pixels to reserve -for the left fringe. Third parameter RIGHT-WIDTH does the same for -the right fringe. Fourth parameter OUTSIDE-MARGINS non-nil specifies -that fringes are drawn outside of the display margins; by default, fringes -are drawn between display marginal areas and the text area. -A nil width parameter means to use the frame's corresponding fringe width. */) + doc: /* Set the fringe widths of window WINDOW. +If WINDOW is nil, set the fringe widths of the currently selected +window. +Second arg LEFT-WIDTH specifies the number of pixels to reserve for +the left fringe. Optional third arg RIGHT-WIDTH specifies the right +fringe width. If a fringe width arg is nil, that means to use the +frame's default fringe width. Default fringe widths can be set with +the command `set-fringe-style'. +If optional fourth arg OUTSIDE-MARGINS is non-nil, draw the fringes +outside of the display margins. By default, fringes are drawn between +display marginal areas and the text area. */) (window, left, right, outside_margins) Lisp_Object window, left, right, outside_margins; { @@ -5834,9 +6028,7 @@ DEFUN ("window-fringes", Fwindow_fringes, Swindow_fringes, 0, 1, 0, doc: /* Get width of fringes of window WINDOW. If WINDOW is omitted or nil, use the currently selected window. -Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS). -If a window specific fringe width is not set, its width will be returned -as nil. */) +Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS). */) (window) Lisp_Object window; { @@ -5861,7 +6053,8 @@ Second parameter WIDTH specifies the pixel width for the scroll bar; this is automatically adjusted to a multiple of the frame column width. Third parameter VERTICAL-TYPE specifies the type of the vertical scroll bar: left, right, or nil. -A width of nil and type of t means to use the frame's corresponding value. */) +If WIDTH is nil, use the frame's scroll-bar width. +If TYPE is t, use the frame's scroll-bar type. */) (window, width, vertical_type, horizontal_type) Lisp_Object window, width, vertical_type, horizontal_type; { @@ -5873,6 +6066,12 @@ A width of nil and type of t means to use the frame's corresponding value. */) if (XINT (width) == 0) vertical_type = Qnil; + if (!(EQ (vertical_type, Qnil) + || EQ (vertical_type, Qleft) + || EQ (vertical_type, Qright) + || EQ (vertical_type, Qt))) + error ("Invalid type of vertical scroll bar"); + if (!EQ (w->scroll_bar_width, width) || !EQ (w->vertical_scroll_bar_type, vertical_type)) { @@ -5896,7 +6095,9 @@ DEFUN ("window-scroll-bars", Fwindow_scroll_bars, Swindow_scroll_bars, 0, 1, 0, doc: /* Get width and type of scroll bars of window WINDOW. If WINDOW is omitted or nil, use the currently selected window. -Value is a list of the form (WIDTH COLS VERTICAL-TYPE HORIZONTAL-TYPE). */) +Value is a list of the form (WIDTH COLS VERTICAL-TYPE HORIZONTAL-TYPE). +If WIDTH is nil or TYPE is t, the window is using the frame's corresponding +value. */) (window) Lisp_Object window; { @@ -6310,6 +6511,11 @@ In the latter case, FUNCTION is called with BUFFER as the first argument, followed by OTHER-ARGS--it can display BUFFER in any way it likes. All this is done by the function found in `special-display-function'. +If the specified frame parameters include (same-buffer . t), the +buffer is displayed in the currently selected window. Otherwise, if +they include (same-frame . t), the buffer is displayed in a new window +in the currently selected frame. + If this variable appears \"not to work\", because you add a name to it but that buffer still appears in the selected window, look at the values of `same-window-buffer-names' and `same-window-regexps'. @@ -6330,6 +6536,11 @@ In the latter case, FUNCTION is called with the buffer as first argument, followed by OTHER-ARGS--it can display the buffer in any way it likes. All this is done by the function found in `special-display-function'. +If the specified frame parameters include (same-buffer . t), the +buffer is displayed in the currently selected window. Otherwise, if +they include (same-frame . t), the buffer is displayed in a new window +in the currently selected frame. + If this variable appears \"not to work\", because you add a regexp to it but the matching buffers still appear in the selected window, look at the values of `same-window-buffer-names' and `same-window-regexps'. @@ -6462,6 +6673,7 @@ This variable automatically becomes buffer-local when set. */); defsubr (&Sspecial_display_p); defsubr (&Ssame_window_p); defsubr (&Sdisplay_buffer); + defsubr (&Sforce_window_update); defsubr (&Ssplit_window); defsubr (&Senlarge_window); defsubr (&Sshrink_window); @@ -6510,3 +6722,6 @@ keys_of_window () initial_define_key (global_map, Ctl('L'), "recenter"); initial_define_key (meta_map, 'r', "move-to-window-line"); } + +/* arch-tag: 90a9c576-0590-48f1-a5f1-6c96a0452d9f + (do not change this comment) */ diff --git a/src/window.h b/src/window.h index cfb1b349d8b..c665e9921c6 100644 --- a/src/window.h +++ b/src/window.h @@ -254,6 +254,9 @@ struct window /* This is handy for undrawing the cursor. */ int phys_cursor_ascent, phys_cursor_height; + /* Alternate overlay-arrow-bitmap in this window. */ + int overlay_arrow_bitmap; + /* Non-zero means the cursor is currently displayed. This can be set to zero by functions overpainting the cursor image. */ unsigned phys_cursor_on_p : 1; @@ -892,3 +895,6 @@ extern void keys_of_window P_ ((void)); extern int window_box_text_cols P_ ((struct window *w)); #endif /* not WINDOW_H_INCLUDED */ + +/* arch-tag: d4a6942f-e433-4ffe-ac10-2c3574f28577 + (do not change this comment) */ diff --git a/src/xdisp.c b/src/xdisp.c index 73ab892d170..6e3fae75376 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -1,5 +1,5 @@ /* Display generation from window structure and buffer text. - Copyright (C) 1985,86,87,88,93,94,95,97,98,99,2000,01,02,03 + Copyright (C) 1985,86,87,88,93,94,95,97,98,99,2000,01,02,03,04 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -243,6 +243,9 @@ Lisp_Object Qbuffer_position, Qposition, Qobject; /* Cursor shapes */ Lisp_Object Qbar, Qhbar, Qbox, Qhollow; +/* Pointer shapes */ +Lisp_Object Qarrow, Qhand, Qtext; + Lisp_Object Qrisky_local_variable; /* Holds the list (error). */ @@ -291,21 +294,44 @@ int inhibit_eval_during_redisplay; /* Names of text properties relevant for redisplay. */ -Lisp_Object Qdisplay, Qrelative_width, Qalign_to; +Lisp_Object Qdisplay; extern Lisp_Object Qface, Qinvisible, Qwidth; /* Symbols used in text property values. */ +Lisp_Object Vdisplay_pixels_per_inch; Lisp_Object Qspace, QCalign_to, QCrelative_width, QCrelative_height; Lisp_Object Qleft_margin, Qright_margin, Qspace_width, Qraise; -Lisp_Object Qmargin; +Lisp_Object Qcenter; +Lisp_Object Qmargin, Qpointer; extern Lisp_Object Qheight; extern Lisp_Object QCwidth, QCheight, QCascent; +extern Lisp_Object Qscroll_bar; /* Non-nil means highlight trailing whitespace. */ Lisp_Object Vshow_trailing_whitespace; +#ifdef HAVE_WINDOW_SYSTEM +extern Lisp_Object Voverflow_newline_into_fringe; + +/* Test if overflow newline into fringe. Called with iterator IT + at or past right window margin, and with IT->current_x set. */ + +#define IT_OVERFLOW_NEWLINE_INTO_FRINGE(it) \ + (!NILP (Voverflow_newline_into_fringe) \ + && FRAME_WINDOW_P (it->f) \ + && WINDOW_RIGHT_FRINGE_WIDTH (it->w) > 0 \ + && it->current_x == it->last_visible_x) + +#endif /* HAVE_WINDOW_SYSTEM */ + +/* Non-nil means show the text cursor in void text areas + i.e. in blank areas after eol and eob. This used to be + the default in 21.3. */ + +Lisp_Object Vvoid_text_area_pointer; + /* Name of the face used to highlight trailing whitespace. */ Lisp_Object Qtrailing_whitespace; @@ -315,6 +341,10 @@ Lisp_Object Qtrailing_whitespace; Lisp_Object Qimage; +/* The image map types. */ +Lisp_Object QCmap, QCpointer; +Lisp_Object Qrect, Qcircle, Qpoly; + /* Non-zero means print newline to stdout before next mini-buffer message. */ @@ -375,6 +405,13 @@ int multiple_frames; Lisp_Object Vglobal_mode_string; + +/* List of variables (symbols) which hold markers for overlay arrows. + The symbols on this list are examined during redisplay to determine + where to display overlay arrows. */ + +Lisp_Object Voverlay_arrow_variable_list; + /* Marker for where to display an arrow on top of the buffer text. */ Lisp_Object Voverlay_arrow_position; @@ -383,11 +420,17 @@ Lisp_Object Voverlay_arrow_position; Lisp_Object Voverlay_arrow_string; -/* Values of those variables at last redisplay. However, if - Voverlay_arrow_position is a marker, last_arrow_position is its +/* Values of those variables at last redisplay are stored as + properties on `overlay-arrow-position' symbol. However, if + Voverlay_arrow_position is a marker, last-arrow-position is its numerical position. */ -static Lisp_Object last_arrow_position, last_arrow_string; +Lisp_Object Qlast_arrow_position, Qlast_arrow_string; + +/* Alternative overlay-arrow-string and overlay-arrow-bitmap + properties on a symbol in overlay-arrow-variable-list. */ + +Lisp_Object Qoverlay_arrow_string, Qoverlay_arrow_bitmap; /* Like mode-line-format, but for the title bar on a visible frame. */ @@ -775,6 +818,7 @@ static int invisible_text_between_p P_ ((struct it *, int, int)); static int next_element_from_ellipsis P_ ((struct it *)); static void pint2str P_ ((char *, int, int)); +static void pint2hrstr P_ ((char *, int, int)); static struct text_pos run_window_scroll_functions P_ ((Lisp_Object, struct text_pos)); static void reconsider_clip_changes P_ ((struct window *, struct buffer *)); @@ -805,10 +849,11 @@ static struct text_pos display_prop_end P_ ((struct it *, Lisp_Object, static int compute_window_start_on_continuation_line P_ ((struct window *)); static Lisp_Object safe_eval_handler P_ ((Lisp_Object)); static void insert_left_trunc_glyphs P_ ((struct it *)); -static struct glyph_row *get_overlay_arrow_glyph_row P_ ((struct window *)); +static struct glyph_row *get_overlay_arrow_glyph_row P_ ((struct window *, + Lisp_Object)); static void extend_face_to_end_of_line P_ ((struct it *)); static int append_space P_ ((struct it *, int)); -static int make_cursor_line_fully_visible P_ ((struct window *)); +static int make_cursor_line_fully_visible P_ ((struct window *, int)); static int try_scrolling P_ ((Lisp_Object, int, EMACS_INT, EMACS_INT, int, int)); static int try_cursor_movement P_ ((Lisp_Object, struct text_pos, int *)); static int trailing_whitespace_p P_ ((int)); @@ -816,6 +861,7 @@ static int message_log_check_duplicate P_ ((int, int, int, int)); static void push_it P_ ((struct it *)); static void pop_it P_ ((struct it *)); static void sync_frame_with_window_matrix_rows P_ ((struct window *)); +static void select_frame_for_redisplay P_ ((Lisp_Object)); static void redisplay_internal P_ ((int)); static int echo_area_display P_ ((int)); static void redisplay_windows P_ ((Lisp_Object)); @@ -1540,6 +1586,10 @@ glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y) ++glyph; } + /* If first glyph is partially visible, its first visible position is still 0. */ + if (hpos < 0) + hpos = 0; + success_p = 1; } else @@ -1571,11 +1621,10 @@ glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y) date. */ static struct glyph * -x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p) +x_y_to_hpos_vpos (w, x, y, hpos, vpos, dx, dy, area) struct window *w; int x, y; - int *hpos, *vpos, *area; - int buffer_only_p; + int *hpos, *vpos, *dx, *dy, *area; { struct glyph *glyph, *end; struct glyph_row *row = NULL; @@ -1614,7 +1663,7 @@ x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p) else if (x < window_box_right_offset (w, TEXT_AREA)) { *area = TEXT_AREA; - x0 = window_box_left_offset (w, TEXT_AREA); + x0 = window_box_left_offset (w, TEXT_AREA) + min (row->x, 0); } else { @@ -1626,23 +1675,22 @@ x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p) /* Find glyph containing X. */ glyph = row->glyphs[*area]; end = glyph + row->used[*area]; - while (glyph < end) + x -= x0; + while (glyph < end && x >= glyph->pixel_width) { - if (x < x0 + glyph->pixel_width) - { - if (w->pseudo_window_p) - break; - else if (!buffer_only_p || BUFFERP (glyph->object)) - break; - } - - x0 += glyph->pixel_width; + x -= glyph->pixel_width; ++glyph; } if (glyph == end) return NULL; + if (dx) + { + *dx = x; + *dy = y - (row->y + row->ascent - glyph->ascent); + } + *hpos = glyph - row->glyphs[*area]; return glyph; } @@ -1730,20 +1778,29 @@ get_glyph_string_clip_rect (s, nr) r.y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r.y); -#ifdef HAVE_NTGUI - /* ++KFS: From W32 port, but it looks ok for all platforms to me. */ /* If drawing the cursor, don't let glyph draw outside its advertised boundaries. Cleartype does this under some circumstances. */ if (s->hl == DRAW_CURSOR) { + struct glyph *glyph = s->first_glyph; + int height; + if (s->x > r.x) { r.width -= s->x - r.x; r.x = s->x; } - r.width = min (r.width, s->first_glyph->pixel_width); + r.width = min (r.width, glyph->pixel_width); + + /* Don't draw cursor glyph taller than our actual glyph. */ + height = max (FRAME_LINE_HEIGHT (s->f), glyph->ascent + glyph->descent); + if (height < r.height) + { + int max_y = r.y + r.height; + r.y = min (max_y, s->ybase + glyph->descent - height); + r.height = min (max_y - r.y, height); + } } -#endif #ifdef CONVERT_FROM_XRECT CONVERT_FROM_XRECT (r, *nr); @@ -1866,10 +1923,14 @@ check_it (it) xassert (STRINGP (it->string)); xassert (IT_STRING_CHARPOS (*it) >= 0); } - else if (it->method == next_element_from_buffer) + else { - /* Check that character and byte positions agree. */ - xassert (IT_CHARPOS (*it) == BYTE_TO_CHAR (IT_BYTEPOS (*it))); + xassert (IT_STRING_CHARPOS (*it) < 0); + if (it->method == next_element_from_buffer) + { + /* Check that character and byte positions agree. */ + xassert (IT_CHARPOS (*it) == BYTE_TO_CHAR (IT_BYTEPOS (*it))); + } } if (it->dpvec) @@ -1982,6 +2043,8 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id) it->current.overlay_string_index = -1; it->current.dpvec_index = -1; it->base_face_id = base_face_id; + it->string = Qnil; + IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1; /* The window in which we iterate over current_buffer: */ XSETWINDOW (it->window, w); @@ -2002,11 +2065,7 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id) attribute changes of named faces, recompute them. When running in batch mode, the face cache of Vterminal_frame is null. If we happen to get called, make a dummy face cache. */ - if ( -#ifndef WINDOWSNT - noninteractive && -#endif - FRAME_FACE_CACHE (it->f) == NULL) + if (noninteractive && FRAME_FACE_CACHE (it->f) == NULL) init_frame_faces (it->f); if (FRAME_FACE_CACHE (it->f)->used == 0) recompute_basic_faces (it->f); @@ -2185,6 +2244,8 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id) else IT_BYTEPOS (*it) = bytepos; + it->start = it->current; + /* Compute faces etc. */ reseat (it, it->current.pos, 1); } @@ -2206,6 +2267,7 @@ start_display (it, w, pos) row = w->desired_matrix->rows + first_vpos; init_iterator (it, w, CHARPOS (pos), BYTEPOS (pos), row, DEFAULT_FACE_ID); + it->first_vpos = first_vpos; if (!it->truncate_lines_p) { @@ -2447,6 +2509,7 @@ init_to_row_start (it, w, row) struct glyph_row *row; { init_from_display_pos (it, w, &row->start); + it->start = row->start; it->continuation_lines_width = row->continuation_lines_width; CHECK_IT (it); } @@ -3240,6 +3303,8 @@ handle_display_prop (it) && !EQ (XCAR (prop), Qraise) /* Marginal area specifications. */ && !(CONSP (XCAR (prop)) && EQ (XCAR (XCAR (prop)), Qmargin)) + && !EQ (XCAR (prop), Qleft_fringe) + && !EQ (XCAR (prop), Qright_fringe) && !NILP (XCAR (prop))) { for (; CONSP (prop); prop = XCDR (prop)) @@ -3464,6 +3529,64 @@ handle_single_display_prop (it, prop, object, position, text properties change there. */ it->stop_charpos = position->charpos; + if (CONSP (prop) + && (EQ (XCAR (prop), Qleft_fringe) + || EQ (XCAR (prop), Qright_fringe)) + && CONSP (XCDR (prop))) + { + unsigned face_id = DEFAULT_FACE_ID; + + /* Save current settings of IT so that we can restore them + when we are finished with the glyph property value. */ + + /* `(left-fringe BITMAP FACE)'. */ + if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f)) + return 0; + +#ifdef HAVE_WINDOW_SYSTEM + value = XCAR (XCDR (prop)); + if (!NUMBERP (value) + || !valid_fringe_bitmap_id_p (XINT (value))) + return 0; + + if (CONSP (XCDR (XCDR (prop)))) + { + Lisp_Object face_name = XCAR (XCDR (XCDR (prop))); + + face_id = lookup_named_face (it->f, face_name); + if (face_id < 0) + return 0; + } + + push_it (it); + + it->area = TEXT_AREA; + it->what = IT_IMAGE; + it->image_id = -1; /* no image */ + it->position = start_pos; + it->object = NILP (object) ? it->w->buffer : object; + it->method = next_element_from_image; + it->face_id = face_id; + + /* Say that we haven't consumed the characters with + `display' property yet. The call to pop_it in + set_iterator_to_next will clean this up. */ + *position = start_pos; + + if (EQ (XCAR (prop), Qleft_fringe)) + { + it->left_user_fringe_bitmap = XINT (value); + it->left_user_fringe_face_id = face_id; + } + else + { + it->right_user_fringe_bitmap = XINT (value); + it->right_user_fringe_face_id = face_id; + } +#endif /* HAVE_WINDOW_SYSTEM */ + return 1; + } + location = Qunbound; if (CONSP (prop) && CONSP (XCAR (prop))) { @@ -3489,16 +3612,11 @@ handle_single_display_prop (it, prop, object, position, value = prop; } + valid_p = (STRINGP (value) #ifdef HAVE_WINDOW_SYSTEM - if (FRAME_TERMCAP_P (it->f)) - valid_p = STRINGP (value); - else - valid_p = (STRINGP (value) - || (CONSP (value) && EQ (XCAR (value), Qspace)) - || valid_image_p (value)); -#else /* not HAVE_WINDOW_SYSTEM */ - valid_p = STRINGP (value); + || (!FRAME_TERMCAP_P (it->f) && valid_image_p (value)) #endif /* not HAVE_WINDOW_SYSTEM */ + || (CONSP (value) && EQ (XCAR (value), Qspace))); if ((EQ (location, Qleft_margin) || EQ (location, Qright_margin) @@ -5578,15 +5696,18 @@ move_it_in_display_line_to (it, to_charpos, to_x, op) saved_glyph_row = it->glyph_row; it->glyph_row = NULL; +#define BUFFER_POS_REACHED_P() \ + ((op & MOVE_TO_POS) != 0 \ + && BUFFERP (it->object) \ + && IT_CHARPOS (*it) >= to_charpos) + while (1) { int x, i, ascent = 0, descent = 0; /* Stop when ZV or TO_CHARPOS reached. */ if (!get_next_display_element (it) - || ((op & MOVE_TO_POS) != 0 - && BUFFERP (it->object) - && IT_CHARPOS (*it) >= to_charpos)) + || BUFFER_POS_REACHED_P ()) { result = MOVE_POS_MATCH_OR_ZV; break; @@ -5668,7 +5789,25 @@ move_it_in_display_line_to (it, to_charpos, to_x, op) ++it->hpos; it->current_x = new_x; if (i == it->nglyphs - 1) - set_iterator_to_next (it, 1); + { + set_iterator_to_next (it, 1); +#ifdef HAVE_WINDOW_SYSTEM + if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) + { + if (!get_next_display_element (it) + || BUFFER_POS_REACHED_P ()) + { + result = MOVE_POS_MATCH_OR_ZV; + break; + } + if (ITERATOR_AT_END_OF_LINE_P (it)) + { + result = MOVE_NEWLINE_OR_CR; + break; + } + } +#endif /* HAVE_WINDOW_SYSTEM */ + } } else { @@ -5725,11 +5864,29 @@ move_it_in_display_line_to (it, to_charpos, to_x, op) if (it->truncate_lines_p && it->current_x >= it->last_visible_x) { +#ifdef HAVE_WINDOW_SYSTEM + if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) + { + if (!get_next_display_element (it) + || BUFFER_POS_REACHED_P ()) + { + result = MOVE_POS_MATCH_OR_ZV; + break; + } + if (ITERATOR_AT_END_OF_LINE_P (it)) + { + result = MOVE_NEWLINE_OR_CR; + break; + } + } +#endif /* HAVE_WINDOW_SYSTEM */ result = MOVE_LINE_TRUNCATED; break; } } +#undef BUFFER_POS_REACHED_P + /* Restore the iterator settings altered at the beginning of this function. */ it->glyph_row = saved_glyph_row; @@ -7663,7 +7820,10 @@ clear_garbaged_frames () if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f)) { if (f->resized_p) - Fredraw_frame (frame); + { + Fredraw_frame (frame); + f->force_flush_display_p = 1; + } clear_current_matrices (f); changed_count++; f->garbaged = 0; @@ -8255,7 +8415,7 @@ update_tool_bar (f, save_match_data) int save_match_data; { #ifdef USE_GTK - int do_update = FRAME_EXTERNAL_TOOL_BAR(f); + int do_update = FRAME_EXTERNAL_TOOL_BAR (f); #else int do_update = WINDOWP (f->tool_bar_window) && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)) > 0; @@ -8319,7 +8479,7 @@ update_tool_bar (f, save_match_data) /* Redisplay the tool-bar if we changed it. */ if (! NILP (Fequal (old_tool_bar, f->tool_bar_items))) w->update_mode_line = Qt; - + UNGCPRO; unbind_to (count, Qnil); @@ -8376,7 +8536,7 @@ build_desired_tool_bar_string (f) int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P)); int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P)); int hmargin, vmargin, relief, idx, end; - extern Lisp_Object QCrelief, QCmargin, QCconversion, Qimage; + extern Lisp_Object QCrelief, QCmargin, QCconversion; /* If image is a vector, choose the image according to the button state. */ @@ -8652,7 +8812,7 @@ redisplay_tool_bar (f) int change_height_p = 0; #ifdef USE_GTK - if (FRAME_EXTERNAL_TOOL_BAR(f)) + if (FRAME_EXTERNAL_TOOL_BAR (f)) update_frame_tool_bar (f); return 0; #endif @@ -8793,7 +8953,7 @@ get_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx) int area; /* Find the glyph under X/Y. */ - *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0); + *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, 0, 0, &area); if (*glyph == NULL) return -1; @@ -8977,283 +9137,6 @@ note_tool_bar_highlight (f, x, y) -/*********************************************************************** - Fringes - ***********************************************************************/ - -#ifdef HAVE_WINDOW_SYSTEM - -/* An arrow like this: `<-'. */ -static unsigned char left_bits[] = { - 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18}; - -/* Right truncation arrow bitmap `->'. */ -static unsigned char right_bits[] = { - 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18}; - -/* Marker for continued lines. */ -static unsigned char continued_bits[] = { - 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c}; - -/* Marker for continuation lines. */ -static unsigned char continuation_bits[] = { - 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e}; - -/* Overlay arrow bitmap. A triangular arrow. */ -static unsigned char ov_bits[] = { - 0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03}; - -/* Bitmap drawn to indicate lines not displaying text if - `indicate-empty-lines' is non-nil. */ -static unsigned char zv_bits[] = { - 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, - 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00}; - -struct fringe_bitmap fringe_bitmaps[MAX_FRINGE_BITMAPS] = -{ - { 0, 0, 0, NULL /* NO_FRINGE_BITMAP */ }, - { 8, sizeof (left_bits), 0, left_bits }, - { 8, sizeof (right_bits), 0, right_bits }, - { 8, sizeof (continued_bits), 0, continued_bits }, - { 8, sizeof (continuation_bits), 0, continuation_bits }, - { 8, sizeof (ov_bits), 0, ov_bits }, - { 8, sizeof (zv_bits), 3, zv_bits } -}; - - -/* Draw the bitmap WHICH in one of the left or right fringes of - window W. ROW is the glyph row for which to display the bitmap; it - determines the vertical position at which the bitmap has to be - drawn. */ - -static void -draw_fringe_bitmap (w, row, which, left_p) - struct window *w; - struct glyph_row *row; - enum fringe_bitmap_type which; - int left_p; -{ - struct frame *f = XFRAME (WINDOW_FRAME (w)); - struct draw_fringe_bitmap_params p; - - /* Convert row to frame coordinates. */ - p.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); - - p.which = which; - p.wd = fringe_bitmaps[which].width; - - p.h = fringe_bitmaps[which].height; - p.dh = (fringe_bitmaps[which].period - ? (p.y % fringe_bitmaps[which].period) - : 0); - p.h -= p.dh; - /* Clip bitmap if too high. */ - if (p.h > row->height) - p.h = row->height; - - p.face = FACE_FROM_ID (f, FRINGE_FACE_ID); - PREPARE_FACE_FOR_DISPLAY (f, p.face); - - /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill - the fringe. */ - p.bx = -1; - if (left_p) - { - int wd = WINDOW_LEFT_FRINGE_WIDTH (w); - int x = window_box_left (w, (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) - ? LEFT_MARGIN_AREA - : TEXT_AREA)); - if (p.wd > wd) - p.wd = wd; - p.x = x - p.wd - (wd - p.wd) / 2; - - if (p.wd < wd || row->height > p.h) - { - /* If W has a vertical border to its left, don't draw over it. */ - wd -= ((!WINDOW_LEFTMOST_P (w) - && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w)) - ? 1 : 0); - p.bx = x - wd; - p.nx = wd; - } - } - else - { - int x = window_box_right (w, - (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) - ? RIGHT_MARGIN_AREA - : TEXT_AREA)); - int wd = WINDOW_RIGHT_FRINGE_WIDTH (w); - if (p.wd > wd) - p.wd = wd; - p.x = x + (wd - p.wd) / 2; - /* Clear right fringe if no bitmap to draw of if bitmap doesn't fill - the fringe. */ - if (p.wd < wd || row->height > p.h) - { - p.bx = x; - p.nx = wd; - } - } - - if (p.bx >= 0) - { - int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w); - - p.by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, row->y)); - p.ny = row->visible_height; - } - - /* Adjust y to the offset in the row to start drawing the bitmap. */ - p.y += (row->height - p.h) / 2; - - rif->draw_fringe_bitmap (w, row, &p); -} - -/* Draw fringe bitmaps for glyph row ROW on window W. Call this - function with input blocked. */ - -void -draw_row_fringe_bitmaps (w, row) - struct window *w; - struct glyph_row *row; -{ - enum fringe_bitmap_type bitmap; - - xassert (interrupt_input_blocked); - - /* If row is completely invisible, because of vscrolling, we - don't have to draw anything. */ - if (row->visible_height <= 0) - return; - - if (WINDOW_LEFT_FRINGE_WIDTH (w) != 0) - { - /* Decide which bitmap to draw in the left fringe. */ - if (row->overlay_arrow_p) - bitmap = OVERLAY_ARROW_BITMAP; - else if (row->truncated_on_left_p) - bitmap = LEFT_TRUNCATION_BITMAP; - else if (MATRIX_ROW_CONTINUATION_LINE_P (row)) - bitmap = CONTINUATION_LINE_BITMAP; - else if (row->indicate_empty_line_p) - bitmap = ZV_LINE_BITMAP; - else - bitmap = NO_FRINGE_BITMAP; - - draw_fringe_bitmap (w, row, bitmap, 1); - } - - if (WINDOW_RIGHT_FRINGE_WIDTH (w) != 0) - { - /* Decide which bitmap to draw in the right fringe. */ - if (row->truncated_on_right_p) - bitmap = RIGHT_TRUNCATION_BITMAP; - else if (row->continued_p) - bitmap = CONTINUED_LINE_BITMAP; - else if (row->indicate_empty_line_p && WINDOW_LEFT_FRINGE_WIDTH (w) == 0) - bitmap = ZV_LINE_BITMAP; - else - bitmap = NO_FRINGE_BITMAP; - - draw_fringe_bitmap (w, row, bitmap, 0); - } -} - - -/* Compute actual fringe widths */ - -void -compute_fringe_widths (f, redraw) - struct frame *f; - int redraw; -{ - int o_left = FRAME_LEFT_FRINGE_WIDTH (f); - int o_right = FRAME_RIGHT_FRINGE_WIDTH (f); - int o_cols = FRAME_FRINGE_COLS (f); - - Lisp_Object left_fringe = Fassq (Qleft_fringe, f->param_alist); - Lisp_Object right_fringe = Fassq (Qright_fringe, f->param_alist); - int left_fringe_width, right_fringe_width; - - if (!NILP (left_fringe)) - left_fringe = Fcdr (left_fringe); - if (!NILP (right_fringe)) - right_fringe = Fcdr (right_fringe); - - left_fringe_width = ((NILP (left_fringe) || !INTEGERP (left_fringe)) ? 8 : - XINT (left_fringe)); - right_fringe_width = ((NILP (right_fringe) || !INTEGERP (right_fringe)) ? 8 : - XINT (right_fringe)); - - if (left_fringe_width || right_fringe_width) - { - int left_wid = left_fringe_width >= 0 ? left_fringe_width : -left_fringe_width; - int right_wid = right_fringe_width >= 0 ? right_fringe_width : -right_fringe_width; - int conf_wid = left_wid + right_wid; - int font_wid = FRAME_COLUMN_WIDTH (f); - int cols = (left_wid + right_wid + font_wid-1) / font_wid; - int real_wid = cols * font_wid; - if (left_wid && right_wid) - { - if (left_fringe_width < 0) - { - /* Left fringe width is fixed, adjust right fringe if necessary */ - FRAME_LEFT_FRINGE_WIDTH (f) = left_wid; - FRAME_RIGHT_FRINGE_WIDTH (f) = real_wid - left_wid; - } - else if (right_fringe_width < 0) - { - /* Right fringe width is fixed, adjust left fringe if necessary */ - FRAME_LEFT_FRINGE_WIDTH (f) = real_wid - right_wid; - FRAME_RIGHT_FRINGE_WIDTH (f) = right_wid; - } - else - { - /* Adjust both fringes with an equal amount. - Note that we are doing integer arithmetic here, so don't - lose a pixel if the total width is an odd number. */ - int fill = real_wid - conf_wid; - FRAME_LEFT_FRINGE_WIDTH (f) = left_wid + fill/2; - FRAME_RIGHT_FRINGE_WIDTH (f) = right_wid + fill - fill/2; - } - } - else if (left_fringe_width) - { - FRAME_LEFT_FRINGE_WIDTH (f) = real_wid; - FRAME_RIGHT_FRINGE_WIDTH (f) = 0; - } - else - { - FRAME_LEFT_FRINGE_WIDTH (f) = 0; - FRAME_RIGHT_FRINGE_WIDTH (f) = real_wid; - } - FRAME_FRINGE_COLS (f) = cols; - } - else - { - FRAME_LEFT_FRINGE_WIDTH (f) = 0; - FRAME_RIGHT_FRINGE_WIDTH (f) = 0; - FRAME_FRINGE_COLS (f) = 0; - } - - if (redraw && FRAME_VISIBLE_P (f)) - if (o_left != FRAME_LEFT_FRINGE_WIDTH (f) || - o_right != FRAME_RIGHT_FRINGE_WIDTH (f) || - o_cols != FRAME_FRINGE_COLS (f)) - redraw_frame (f); -} - -#endif /* HAVE_WINDOW_SYSTEM */ - - - /************************************************************************ Horizontal scrolling ************************************************************************/ @@ -9354,7 +9237,10 @@ hscroll_window_tree (window) /* Position cursor in window. */ if (!hscroll_relative_p && hscroll_step_abs == 0) - hscroll = max (0, it.current_x - text_area_width / 2) + hscroll = max (0, (it.current_x + - (ITERATOR_AT_END_OF_LINE_P (&it) + ? (text_area_width - 4 * FRAME_COLUMN_WIDTH (it.f)) + : (text_area_width / 2)))) / FRAME_COLUMN_WIDTH (it.f); else if (w->cursor.x >= text_area_width - h_margin) { @@ -9563,6 +9449,153 @@ redisplay () } +static Lisp_Object +overlay_arrow_string_or_property (var, pbitmap) + Lisp_Object var; + int *pbitmap; +{ + Lisp_Object pstr = Fget (var, Qoverlay_arrow_string); + Lisp_Object bitmap; + + if (pbitmap) + { + *pbitmap = 0; + if (bitmap = Fget (var, Qoverlay_arrow_bitmap), INTEGERP (bitmap)) + *pbitmap = XINT (bitmap); + } + + if (!NILP (pstr)) + return pstr; + return Voverlay_arrow_string; +} + +/* Return 1 if there are any overlay-arrows in current_buffer. */ +static int +overlay_arrow_in_current_buffer_p () +{ + Lisp_Object vlist; + + for (vlist = Voverlay_arrow_variable_list; + CONSP (vlist); + vlist = XCDR (vlist)) + { + Lisp_Object var = XCAR (vlist); + Lisp_Object val; + + if (!SYMBOLP (var)) + continue; + val = find_symbol_value (var); + if (MARKERP (val) + && current_buffer == XMARKER (val)->buffer) + return 1; + } + return 0; +} + + +/* Return 1 if any overlay_arrows have moved or overlay-arrow-string + has changed. */ + +static int +overlay_arrows_changed_p () +{ + Lisp_Object vlist; + + for (vlist = Voverlay_arrow_variable_list; + CONSP (vlist); + vlist = XCDR (vlist)) + { + Lisp_Object var = XCAR (vlist); + Lisp_Object val, pstr; + + if (!SYMBOLP (var)) + continue; + val = find_symbol_value (var); + if (!MARKERP (val)) + continue; + if (! EQ (COERCE_MARKER (val), + Fget (var, Qlast_arrow_position)) + || ! (pstr = overlay_arrow_string_or_property (var, 0), + EQ (pstr, Fget (var, Qlast_arrow_string)))) + return 1; + } + return 0; +} + +/* Mark overlay arrows to be updated on next redisplay. */ + +static void +update_overlay_arrows (up_to_date) + int up_to_date; +{ + Lisp_Object vlist; + + for (vlist = Voverlay_arrow_variable_list; + CONSP (vlist); + vlist = XCDR (vlist)) + { + Lisp_Object var = XCAR (vlist); + + if (!SYMBOLP (var)) + continue; + + if (up_to_date) + { + Lisp_Object val = find_symbol_value (var); + Fput (var, Qlast_arrow_position, + COERCE_MARKER (val)); + Fput (var, Qlast_arrow_string, + overlay_arrow_string_or_property (var, 0)); + } + else if (up_to_date < 0 + || !NILP (Fget (var, Qlast_arrow_position))) + { + Fput (var, Qlast_arrow_position, Qt); + Fput (var, Qlast_arrow_string, Qt); + } + } +} + + +/* Return overlay arrow string at row, or nil. */ + +static Lisp_Object +overlay_arrow_at_row (f, row, pbitmap) + struct frame *f; + struct glyph_row *row; + int *pbitmap; +{ + Lisp_Object vlist; + + for (vlist = Voverlay_arrow_variable_list; + CONSP (vlist); + vlist = XCDR (vlist)) + { + Lisp_Object var = XCAR (vlist); + Lisp_Object val; + + if (!SYMBOLP (var)) + continue; + + val = find_symbol_value (var); + + if (MARKERP (val) + && current_buffer == XMARKER (val)->buffer + && (MATRIX_ROW_START_CHARPOS (row) == marker_position (val))) + { + val = overlay_arrow_string_or_property (var, pbitmap); + if (FRAME_WINDOW_P (f)) + return Qt; + else if (STRINGP (val)) + return val; + break; + } + } + + *pbitmap = 0; + return Qnil; +} + /* Return 1 if point moved out of or into a composition. Otherwise return 0. PREV_BUF and PREV_PT are the last point buffer and position. BUF and PT are the current point buffer and position. */ @@ -9641,6 +9674,44 @@ reconsider_clip_changes (w, b) } } + +/* Select FRAME to forward the values of frame-local variables into C + variables so that the redisplay routines can access those values + directly. */ + +static void +select_frame_for_redisplay (frame) + Lisp_Object frame; +{ + Lisp_Object tail, sym, val; + Lisp_Object old = selected_frame; + + selected_frame = frame; + + for (tail = XFRAME (frame)->param_alist; CONSP (tail); tail = XCDR (tail)) + if (CONSP (XCAR (tail)) + && (sym = XCAR (XCAR (tail)), + SYMBOLP (sym)) + && (sym = indirect_variable (sym), + val = SYMBOL_VALUE (sym), + (BUFFER_LOCAL_VALUEP (val) + || SOME_BUFFER_LOCAL_VALUEP (val))) + && XBUFFER_LOCAL_VALUE (val)->check_frame) + Fsymbol_value (sym); + + for (tail = XFRAME (old)->param_alist; CONSP (tail); tail = XCDR (tail)) + if (CONSP (XCAR (tail)) + && (sym = XCAR (XCAR (tail)), + SYMBOLP (sym)) + && (sym = indirect_variable (sym), + val = SYMBOL_VALUE (sym), + (BUFFER_LOCAL_VALUEP (val) + || SOME_BUFFER_LOCAL_VALUEP (val))) + && XBUFFER_LOCAL_VALUE (val)->check_frame) + Fsymbol_value (sym); +} + + #define STOP_POLLING \ do { if (! polling_stopped_here) stop_polling (); \ polling_stopped_here = 1; } while (0) @@ -9706,7 +9777,8 @@ redisplay_internal (preserve_echo_area) /* Record a function that resets redisplaying_p to its old value when we leave this function. */ count = SPECPDL_INDEX (); - record_unwind_protect (unwind_redisplay, make_number (redisplaying_p)); + record_unwind_protect (unwind_redisplay, + Fcons (make_number (redisplaying_p), selected_frame)); ++redisplaying_p; specbind (Qinhibit_free_realized_faces, Qnil); @@ -9803,8 +9875,7 @@ redisplay_internal (preserve_echo_area) /* If specs for an arrow have changed, do thorough redisplay to ensure we remove any arrow that should no longer exist. */ - if (! EQ (COERCE_MARKER (Voverlay_arrow_position), last_arrow_position) - || ! EQ (Voverlay_arrow_string, last_arrow_string)) + if (overlay_arrows_changed_p ()) consider_all_windows_p = windows_or_buffers_changed = 1; /* Normally the message* functions will have already displayed and @@ -10016,6 +10087,9 @@ redisplay_internal (preserve_echo_area) *w->desired_matrix->method = 0; debug_method_add (w, "optimization 1"); #endif +#ifdef HAVE_WINDOW_SYSTEM + update_window_fringes (w, 0); +#endif goto update; } else @@ -10120,6 +10194,11 @@ redisplay_internal (preserve_echo_area) if (FRAME_WINDOW_P (f) || f == sf) { + if (! EQ (frame, selected_frame)) + /* Select the frame, for the sake of frame-local + variables. */ + select_frame_for_redisplay (frame); + #ifdef HAVE_WINDOW_SYSTEM if (clear_face_cache_count % 50 == 0 && FRAME_WINDOW_P (f)) @@ -10180,15 +10259,18 @@ redisplay_internal (preserve_echo_area) } } - /* Do the mark_window_display_accurate after all windows have - been redisplayed because this call resets flags in buffers - which are needed for proper redisplay. */ - for (i = 0; i < n; ++i) + if (!pause) { - struct frame *f = updated[i]; - mark_window_display_accurate (f->root_window, 1); - if (frame_up_to_date_hook) - frame_up_to_date_hook (f); + /* Do the mark_window_display_accurate after all windows have + been redisplayed because this call resets flags in buffers + which are needed for proper redisplay. */ + for (i = 0; i < n; ++i) + { + struct frame *f = updated[i]; + mark_window_display_accurate (f->root_window, 1); + if (frame_up_to_date_hook) + frame_up_to_date_hook (f); + } } } else if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf)) @@ -10253,11 +10335,7 @@ redisplay_internal (preserve_echo_area) CHARPOS (this_line_start_pos) = 0; /* Let the overlay arrow be updated the next time. */ - if (!NILP (last_arrow_position)) - { - last_arrow_position = Qt; - last_arrow_string = Qt; - } + update_overlay_arrows (0); /* If we pause after scrolling, some rows in the current matrices of some windows are not valid. */ @@ -10273,8 +10351,8 @@ redisplay_internal (preserve_echo_area) consider_all_windows_p is set. */ mark_window_display_accurate_1 (w, 1); - last_arrow_position = COERCE_MARKER (Voverlay_arrow_position); - last_arrow_string = Voverlay_arrow_string; + /* Say overlay arrows are up to date. */ + update_overlay_arrows (1); if (frame_up_to_date_hook != 0) frame_up_to_date_hook (sf); @@ -10369,13 +10447,20 @@ redisplay_preserve_echo_area (from_where) /* Function registered with record_unwind_protect in redisplay_internal. Reset redisplaying_p to the value it had before redisplay_internal was called, and clear - prevent_freeing_realized_faces_p. */ + prevent_freeing_realized_faces_p. It also selects the previously + selected frame. */ static Lisp_Object -unwind_redisplay (old_redisplaying_p) - Lisp_Object old_redisplaying_p; +unwind_redisplay (val) + Lisp_Object val; { + Lisp_Object old_redisplaying_p, old_frame; + + old_redisplaying_p = XCAR (val); redisplaying_p = XFASTINT (old_redisplaying_p); + old_frame = XCDR (val); + if (! EQ (old_frame, selected_frame)) + select_frame_for_redisplay (old_frame); return Qnil; } @@ -10463,16 +10548,14 @@ mark_window_display_accurate (window, accurate_p) if (accurate_p) { - last_arrow_position = COERCE_MARKER (Voverlay_arrow_position); - last_arrow_string = Voverlay_arrow_string; + update_overlay_arrows (1); } else { /* Force a thorough redisplay the next time by setting last_arrow_position and last_arrow_string to t, which is unequal to any useful value of Voverlay_arrow_... */ - last_arrow_position = Qt; - last_arrow_string = Qt; + update_overlay_arrows (-1); } } @@ -10751,12 +10834,17 @@ run_window_scroll_functions (window, startp) A value of 1 means there is nothing to be done. (Either the line is fully visible, or it cannot be made so, or we cannot tell.) + + If FORCE_P is non-zero, return 0 even if partial visible cursor row + is higher than window. + A value of 0 means the caller should do scrolling as if point had gone off the screen. */ static int -make_cursor_line_fully_visible (w) +make_cursor_line_fully_visible (w, force_p) struct window *w; + int force_p; { struct glyph_matrix *matrix; struct glyph_row *row; @@ -10774,6 +10862,9 @@ make_cursor_line_fully_visible (w) if (!MATRIX_ROW_PARTIALLY_VISIBLE_P (row)) return 1; + if (force_p) + return 0; + /* If the row the cursor is in is taller than the window's height, it's not clear what to do, so do nothing. */ window_height = window_box_height (w); @@ -10870,7 +10961,7 @@ try_scrolling (window, just_this_one_p, scroll_conservatively, int amount_to_scroll = 0; Lisp_Object aggressive; int height; - int end_scroll_margin; + int extra_scroll_margin_lines = last_line_misfit ? 1 : 0; #if GLYPH_DEBUG debug_method_add (w, "try_scrolling"); @@ -10913,11 +11004,13 @@ try_scrolling (window, just_this_one_p, scroll_conservatively, CHARPOS (scroll_margin_pos) = XINT (window_end); BYTEPOS (scroll_margin_pos) = CHAR_TO_BYTE (CHARPOS (scroll_margin_pos)); - end_scroll_margin = this_scroll_margin + !!last_line_misfit; - if (end_scroll_margin) + if (this_scroll_margin || extra_scroll_margin_lines) { start_display (&it, w, scroll_margin_pos); - move_it_vertically (&it, - end_scroll_margin); + if (this_scroll_margin) + move_it_vertically (&it, - this_scroll_margin); + if (extra_scroll_margin_lines) + move_it_by_lines (&it, - extra_scroll_margin_lines, 0); scroll_margin_pos = it.current.pos; } @@ -11052,10 +11145,10 @@ try_scrolling (window, just_this_one_p, scroll_conservatively, /* If cursor ends up on a partially visible line, treat that as being off the bottom of the screen. */ - if (! make_cursor_line_fully_visible (w)) + if (! make_cursor_line_fully_visible (w, extra_scroll_margin_lines <= 1)) { clear_glyph_matrix (w->desired_matrix); - last_line_misfit = 1; + ++extra_scroll_margin_lines; goto too_near_end; } rc = SCROLLING_SUCCESS; @@ -11212,8 +11305,7 @@ try_cursor_movement (window, startp, scroll_step) && INTEGERP (w->window_end_vpos) && XFASTINT (w->window_end_vpos) < w->current_matrix->nrows && (FRAME_WINDOW_P (f) - || !MARKERP (Voverlay_arrow_position) - || current_buffer != XMARKER (Voverlay_arrow_position)->buffer)) + || !overlay_arrow_in_current_buffer_p ())) { int this_scroll_margin; struct glyph_row *row = NULL; @@ -11345,7 +11437,7 @@ try_cursor_movement (window, startp, scroll_step) else { set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0); - if (!make_cursor_line_fully_visible (w)) + if (!make_cursor_line_fully_visible (w, 0)) rc = CURSOR_MOVEMENT_MUST_SCROLL; else rc = CURSOR_MOVEMENT_SUCCESS; @@ -11375,7 +11467,7 @@ set_vertical_scroll_bar (w) which reflect the whole buffer size, with special markers indicating narrowing, and scrollbars which reflect only the visible region. - + Note that mini-buffers sometimes aren't displaying any text. */ if (!MINI_WINDOW_P (w) || (w == XWINDOW (minibuf_window) @@ -11387,7 +11479,7 @@ set_vertical_scroll_bar (w) /* I don't think this is guaranteed to be right. For the moment, we'll pretend it is. */ end = BUF_Z (buf) - XFASTINT (w->window_end_pos) - BUF_BEGV (buf); - + if (end < start) end = start; if (whole < (end - start)) @@ -11400,6 +11492,7 @@ set_vertical_scroll_bar (w) set_vertical_scroll_bar_hook (w, end - start, whole, start); } + /* Redisplay leaf window WINDOW. JUST_THIS_ONE_P non-zero means only selected_window is redisplayed. @@ -11422,6 +11515,7 @@ redisplay_window (window, just_this_one_p) struct it it; /* Record it now because it's overwritten. */ int current_matrix_up_to_date_p = 0; + int used_current_matrix_p = 0; /* This is less strict than current_matrix_up_to_date_p. It indictes that the buffer contents and narrowing are unchanged. */ int buffer_unchanged_p = 0; @@ -11612,6 +11706,11 @@ redisplay_window (window, just_this_one_p) MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y); if (IT_CHARPOS (it) == PT) w->force_start = Qt; + /* IT may overshoot PT if text at PT is invisible. */ + else if (IT_CHARPOS (it) > PT && CHARPOS (startp) <= PT) + w->force_start = Qt; + + } /* Handle case where place to start displaying has been specified, @@ -11669,7 +11768,7 @@ redisplay_window (window, just_this_one_p) new_vpos = window_box_height (w) / 2; } - if (!make_cursor_line_fully_visible (w)) + if (!make_cursor_line_fully_visible (w, 0)) { /* Point does appear, but on a line partly visible at end of window. Move it back to a fully-visible line. */ @@ -11723,6 +11822,7 @@ redisplay_window (window, just_this_one_p) switch (rc) { case CURSOR_MOVEMENT_SUCCESS: + used_current_matrix_p = 1; goto done; #if 0 /* try_cursor_movement never returns this value. */ @@ -11787,7 +11887,8 @@ redisplay_window (window, just_this_one_p) buffer. */ || !NILP (Vwindow_scroll_functions) || MINI_WINDOW_P (w) - || !try_window_reusing_current_matrix (w)) + || !(used_current_matrix_p = + try_window_reusing_current_matrix (w))) { IF_DEBUG (debug_method_add (w, "1")); try_window (window, startp); @@ -11804,7 +11905,7 @@ redisplay_window (window, just_this_one_p) /* Forget any recorded base line for line number display. */ w->base_line_number = Qnil; - if (!make_cursor_line_fully_visible (w)) + if (!make_cursor_line_fully_visible (w, 1)) { clear_glyph_matrix (w->desired_matrix); last_line_misfit = 1; @@ -11916,7 +12017,8 @@ redisplay_window (window, just_this_one_p) || !NILP (Vwindow_scroll_functions) || !just_this_one_p || MINI_WINDOW_P (w) - || !try_window_reusing_current_matrix (w)) + || !(used_current_matrix_p = + try_window_reusing_current_matrix (w))) try_window (window, startp); /* If new fonts have been loaded (due to fontsets), give up. We @@ -11963,7 +12065,7 @@ redisplay_window (window, just_this_one_p) set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0); } - if (!make_cursor_line_fully_visible (w)) + if (!make_cursor_line_fully_visible (w, centering_position > 0)) { /* If vscroll is enabled, disable it and try again. */ if (w->vscroll) @@ -11976,6 +12078,7 @@ redisplay_window (window, just_this_one_p) /* If centering point failed to make the whole line visible, put point at the top instead. That has to make the whole line visible, if it can be done. */ + clear_glyph_matrix (w->desired_matrix); centering_position = 0; goto point_at_top; } @@ -12078,6 +12181,20 @@ redisplay_window (window, just_this_one_p) #endif } +#ifdef HAVE_WINDOW_SYSTEM + if (update_window_fringes (w, 0) + && !just_this_one_p + && (used_current_matrix_p || overlay_arrow_seen) + && !w->pseudo_window_p) + { + update_begin (f); + BLOCK_INPUT; + draw_window_fringes (w); + UNBLOCK_INPUT; + update_end (f); + } +#endif /* HAVE_WINDOW_SYSTEM */ + /* We go to this label, with fonts_changed_p nonzero, if it is necessary to try again using larger glyph matrices. We have to redeem the scroll bar even in this case, @@ -12334,6 +12451,7 @@ try_window_reusing_current_matrix (w) row->visible_height -= min_y - row->y; if (row->y + row->height > max_y) row->visible_height -= row->y + row->height - max_y; + row->redraw_fringe_bitmaps_p = 1; it.current_y += row->height; @@ -12473,7 +12591,6 @@ try_window_reusing_current_matrix (w) if (run.height) { - struct frame *f = XFRAME (WINDOW_FRAME (w)); update_begin (f); rif->update_window_begin_hook (w); rif->clear_window_mouse_face (w); @@ -12494,6 +12611,7 @@ try_window_reusing_current_matrix (w) row->visible_height -= min_y - row->y; if (row->y + row->height > max_y) row->visible_height -= row->y + row->height - max_y; + row->redraw_fringe_bitmaps_p = 1; } /* Scroll the current matrix. */ @@ -12616,7 +12734,8 @@ find_last_unchanged_at_beg_row (w) row is not unchanged because it may be no longer continued. */ && !(MATRIX_ROW_END_CHARPOS (row) == first_changed_pos - && row->continued_p)) + && (row->continued_p + || row->exact_window_width_line_p))) row_found = row; /* Stop if last visible row. */ @@ -12936,8 +13055,7 @@ try_window_id (w) GIVE_UP (10); /* Can use this if overlay arrow position and or string have changed. */ - if (!EQ (last_arrow_position, COERCE_MARKER (Voverlay_arrow_position)) - || !EQ (last_arrow_string, Voverlay_arrow_string)) + if (overlay_arrows_changed_p ()) GIVE_UP (12); @@ -13125,8 +13243,9 @@ try_window_id (w) else { /* There are no reusable lines at the start of the window. - Start displaying in the first line. */ + Start displaying in the first text line. */ start_display (&it, w, start); + it.vpos = it.first_vpos; start_pos = it.current.pos; } @@ -13873,14 +13992,15 @@ usage: (trace-to-stderr STRING &rest OBJECTS) */) arrow. Only used for non-window-redisplay windows. */ static struct glyph_row * -get_overlay_arrow_glyph_row (w) +get_overlay_arrow_glyph_row (w, overlay_arrow_string) struct window *w; + Lisp_Object overlay_arrow_string; { struct frame *f = XFRAME (WINDOW_FRAME (w)); struct buffer *buffer = XBUFFER (w->buffer); struct buffer *old = current_buffer; - const unsigned char *arrow_string = SDATA (Voverlay_arrow_string); - int arrow_len = SCHARS (Voverlay_arrow_string); + const unsigned char *arrow_string = SDATA (overlay_arrow_string); + int arrow_len = SCHARS (overlay_arrow_string); const unsigned char *arrow_end = arrow_string + arrow_len; const unsigned char *p; struct it it; @@ -13907,7 +14027,7 @@ get_overlay_arrow_glyph_row (w) /* Get its face. */ ilisp = make_number (p - arrow_string); - face = Fget_text_property (ilisp, Qface, Voverlay_arrow_string); + face = Fget_text_property (ilisp, Qface, overlay_arrow_string); it.face_id = compute_char_face (f, it.c, face); /* Compute its width, get its glyphs. */ @@ -14346,6 +14466,8 @@ display_line (it) struct it *it; { struct glyph_row *row = it->glyph_row; + int overlay_arrow_bitmap; + Lisp_Object overlay_arrow_string; /* We always start displaying at hpos zero even if hscrolled. */ xassert (it->hpos == 0 && it->current_x == 0); @@ -14361,7 +14483,7 @@ display_line (it) prepare_desired_row (row); row->y = it->current_y; - row->start = it->current; + row->start = it->start; row->continuation_lines_width = it->continuation_lines_width; row->displays_text_p = 1; row->starts_in_middle_of_char_p = it->starts_in_middle_of_char_p; @@ -14404,6 +14526,11 @@ display_line (it) display the cursor there under X. Set the charpos of the first glyph of blank lines not corresponding to any text to -1. */ +#ifdef HAVE_WINDOW_SYSTEM + if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) + row->exact_window_width_line_p = 1; + else +#endif /* HAVE_WINDOW_SYSTEM */ if ((append_space (it, 1) && row->used[TEXT_AREA] == 1) || row->used[TEXT_AREA] == 0) { @@ -14511,7 +14638,26 @@ display_line (it) it->continuation_lines_width += new_x; ++it->hpos; if (i == nglyphs - 1) - set_iterator_to_next (it, 1); + { + set_iterator_to_next (it, 1); +#ifdef HAVE_WINDOW_SYSTEM + if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) + { + if (!get_next_display_element (it)) + { + row->exact_window_width_line_p = 1; + it->continuation_lines_width = 0; + row->continued_p = 0; + row->ends_at_zv_p = 1; + } + else if (ITERATOR_AT_END_OF_LINE_P (it)) + { + row->continued_p = 0; + row->exact_window_width_line_p = 1; + } + } +#endif /* HAVE_WINDOW_SYSTEM */ + } } else if (CHAR_GLYPH_PADDING_P (*glyph) && !FRAME_WINDOW_P (it->f)) @@ -14609,10 +14755,11 @@ display_line (it) it->max_phys_ascent + it->max_phys_descent); /* End of this display line if row is continued. */ - if (row->continued_p) + if (row->continued_p || row->ends_at_zv_p) break; } + at_end_of_line: /* Is this a line end? If yes, we're also done, after making sure that a non-default face is extended up to the right margin of the window. */ @@ -14622,9 +14769,12 @@ display_line (it) row->ends_in_newline_from_string_p = STRINGP (it->object); +#ifdef HAVE_WINDOW_SYSTEM /* Add a space at the end of the line that is used to display the cursor there. */ - append_space (it, 0); + if (!IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) + append_space (it, 0); +#endif /* HAVE_WINDOW_SYSTEM */ /* Extend the face to the end of the line. */ extend_face_to_end_of_line (it); @@ -14665,6 +14815,29 @@ display_line (it) produce_special_glyphs (it, IT_TRUNCATION); } } +#ifdef HAVE_WINDOW_SYSTEM + else + { + /* Don't truncate if we can overflow newline into fringe. */ + if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it)) + { + if (!get_next_display_element (it)) + { +#ifdef HAVE_WINDOW_SYSTEM + it->continuation_lines_width = 0; + row->ends_at_zv_p = 1; + row->exact_window_width_line_p = 1; + break; +#endif /* HAVE_WINDOW_SYSTEM */ + } + if (ITERATOR_AT_END_OF_LINE_P (it)) + { + row->exact_window_width_line_p = 1; + goto at_end_of_line; + } + } + } +#endif /* HAVE_WINDOW_SYSTEM */ row->truncated_on_right_p = 1; it->continuation_lines_width = 0; @@ -14690,17 +14863,16 @@ display_line (it) mark this glyph row as the one containing the overlay arrow. This is clearly a mess with variable size fonts. It would be better to let it be displayed like cursors under X. */ - if (MARKERP (Voverlay_arrow_position) - && current_buffer == XMARKER (Voverlay_arrow_position)->buffer - && (MATRIX_ROW_START_CHARPOS (row) - == marker_position (Voverlay_arrow_position)) - && STRINGP (Voverlay_arrow_string) - && ! overlay_arrow_seen) + if (! overlay_arrow_seen + && (overlay_arrow_string + = overlay_arrow_at_row (it->f, row, &overlay_arrow_bitmap), + !NILP (overlay_arrow_string))) { /* Overlay arrow in window redisplay is a fringe bitmap. */ if (!FRAME_WINDOW_P (it->f)) { - struct glyph_row *arrow_row = get_overlay_arrow_glyph_row (it->w); + struct glyph_row *arrow_row + = get_overlay_arrow_glyph_row (it->w, overlay_arrow_string); struct glyph *glyph = arrow_row->glyphs[TEXT_AREA]; struct glyph *arrow_end = glyph + arrow_row->used[TEXT_AREA]; struct glyph *p = row->glyphs[TEXT_AREA]; @@ -14724,6 +14896,7 @@ display_line (it) } overlay_arrow_seen = 1; + it->w->overlay_arrow_bitmap = overlay_arrow_bitmap; row->overlay_arrow_p = 1; } @@ -14733,6 +14906,17 @@ display_line (it) /* Remember the position at which this line ends. */ row->end = it->current; + /* Save fringe bitmaps in this row. */ + row->left_user_fringe_bitmap = it->left_user_fringe_bitmap; + row->left_user_fringe_face_id = it->left_user_fringe_face_id; + row->right_user_fringe_bitmap = it->right_user_fringe_bitmap; + row->right_user_fringe_face_id = it->right_user_fringe_face_id; + + it->left_user_fringe_bitmap = 0; + it->left_user_fringe_face_id = 0; + it->right_user_fringe_bitmap = 0; + it->right_user_fringe_face_id = 0; + /* Maybe set the cursor. */ if (it->w->cursor.vpos < 0 && PT >= MATRIX_ROW_START_CHARPOS (row) @@ -14752,6 +14936,7 @@ display_line (it) it->current_y += row->height; ++it->vpos; ++it->glyph_row; + it->start = it->current; return row->displays_text_p; } @@ -14995,6 +15180,8 @@ display_mode_line (w, face_id, format) init_iterator (&it, w, -1, -1, NULL, face_id); prepare_desired_row (it.glyph_row); + it.glyph_row->mode_line_p = 1; + if (! mode_line_inverse_video) /* Force the mode-line to be displayed in the default face. */ it.base_face_id = it.face_id = DEFAULT_FACE_ID; @@ -15011,7 +15198,6 @@ display_mode_line (w, face_id, format) compute_line_metrics (&it); it.glyph_row->full_width_p = 1; - it.glyph_row->mode_line_p = 1; it.glyph_row->continued_p = 0; it.glyph_row->truncated_on_left_p = 0; it.glyph_row->truncated_on_right_p = 0; @@ -15683,6 +15869,117 @@ pint2str (buf, width, d) } } +/* Write a null-terminated, right justified decimal and "human + readable" representation of the nonnegative integer D to BUF using + a minimal field width WIDTH. D should be smaller than 999.5e24. */ + +static const char power_letter[] = + { + 0, /* not used */ + 'k', /* kilo */ + 'M', /* mega */ + 'G', /* giga */ + 'T', /* tera */ + 'P', /* peta */ + 'E', /* exa */ + 'Z', /* zetta */ + 'Y' /* yotta */ + }; + +static void +pint2hrstr (buf, width, d) + char *buf; + int width; + int d; +{ + /* We aim to represent the nonnegative integer D as + QUOTIENT.TENTHS * 10 ^ (3 * EXPONENT). */ + int quotient = d; + int remainder = 0; + /* -1 means: do not use TENTHS. */ + int tenths = -1; + int exponent = 0; + + /* Length of QUOTIENT.TENTHS as a string. */ + int length; + + char * psuffix; + char * p; + + if (1000 <= quotient) + { + /* Scale to the appropriate EXPONENT. */ + do + { + remainder = quotient % 1000; + quotient /= 1000; + exponent++; + } + while (1000 <= quotient); + + /* Round to nearest and decide whether to use TENTHS or not. */ + if (quotient <= 9) + { + tenths = remainder / 100; + if (50 <= remainder % 100) + if (tenths < 9) + tenths++; + else + { + quotient++; + if (quotient == 10) + tenths = -1; + else + tenths = 0; + } + } + else + if (500 <= remainder) + if (quotient < 999) + quotient++; + else + { + quotient = 1; + exponent++; + tenths = 0; + } + } + + /* Calculate the LENGTH of QUOTIENT.TENTHS as a string. */ + if (tenths == -1 && quotient <= 99) + if (quotient <= 9) + length = 1; + else + length = 2; + else + length = 3; + p = psuffix = buf + max (width, length); + + /* Print EXPONENT. */ + if (exponent) + *psuffix++ = power_letter[exponent]; + *psuffix = '\0'; + + /* Print TENTHS. */ + if (tenths >= 0) + { + *--p = '0' + tenths; + *--p = '.'; + } + + /* Print QUOTIENT. */ + do + { + int digit = quotient % 10; + *--p = '0' + digit; + } + while ((quotient /= 10) != 0); + + /* Print leading spaces. */ + while (buf < p) + *--p = ' '; +} + /* Set a mnemonic character for coding_system (Lisp symbol) in BUF. If EOL_FLAG is 1, set also a mnemonic character for end-of-line type of CODING_SYSTEM. Return updated pointer into BUF. */ @@ -15886,6 +16183,20 @@ decode_mode_spec (w, c, field_width, precision, multibyte) obj = b->filename; break; + case 'i': + { + int size = ZV - BEGV; + pint2str (decode_mode_spec_buf, field_width, size); + return decode_mode_spec_buf; + } + + case 'I': + { + int size = ZV - BEGV; + pint2hrstr (decode_mode_spec_buf, field_width, size); + return decode_mode_spec_buf; + } + case 'l': { int startpos = XMARKER (w->start)->charpos; @@ -16503,6 +16814,252 @@ invisible_p (propval, list) return 0; } +/* Calculate a width or height in pixels from a specification using + the following elements: + + SPEC ::= + NUM - a (fractional) multiple of the default font width/height + (NUM) - specifies exactly NUM pixels + UNIT - a fixed number of pixels, see below. + ELEMENT - size of a display element in pixels, see below. + (NUM . SPEC) - equals NUM * SPEC + (+ SPEC SPEC ...) - add pixel values + (- SPEC SPEC ...) - subtract pixel values + (- SPEC) - negate pixel value + + NUM ::= + INT or FLOAT - a number constant + SYMBOL - use symbol's (buffer local) variable binding. + + UNIT ::= + in - pixels per inch *) + mm - pixels per 1/1000 meter *) + cm - pixels per 1/100 meter *) + width - width of current font in pixels. + height - height of current font in pixels. + + *) using the ratio(s) defined in display-pixels-per-inch. + + ELEMENT ::= + + left-fringe - left fringe width in pixels + right-fringe - right fringe width in pixels + + left-margin - left margin width in pixels + right-margin - right margin width in pixels + + scroll-bar - scroll-bar area width in pixels + + Examples: + + Pixels corresponding to 5 inches: + (5 . in) + + Total width of non-text areas on left side of window (if scroll-bar is on left): + '(space :width (+ left-fringe left-margin scroll-bar)) + + Align to first text column (in header line): + '(space :align-to 0) + + Align to middle of text area minus half the width of variable `my-image' + containing a loaded image: + '(space :align-to (0.5 . (- text my-image))) + + Width of left margin minus width of 1 character in the default font: + '(space :width (- left-margin 1)) + + Width of left margin minus width of 2 characters in the current font: + '(space :width (- left-margin (2 . width))) + + Center 1 character over left-margin (in header line): + '(space :align-to (+ left-margin (0.5 . left-margin) -0.5)) + + Different ways to express width of left fringe plus left margin minus one pixel: + '(space :width (- (+ left-fringe left-margin) (1))) + '(space :width (+ left-fringe left-margin (- (1)))) + '(space :width (+ left-fringe left-margin (-1))) + +*/ + +#define NUMVAL(X) \ + ((INTEGERP (X) || FLOATP (X)) \ + ? XFLOATINT (X) \ + : - 1) + +int +calc_pixel_width_or_height (res, it, prop, font, width_p, align_to) + double *res; + struct it *it; + Lisp_Object prop; + void *font; + int width_p, *align_to; +{ + double pixels; + +#define OK_PIXELS(val) ((*res = (double)(val)), 1) +#define OK_ALIGN_TO(val) ((*align_to = (int)(val)), 1) + + if (NILP (prop)) + return OK_PIXELS (0); + + if (SYMBOLP (prop)) + { + if (SCHARS (SYMBOL_NAME (prop)) == 2) + { + char *unit = SDATA (SYMBOL_NAME (prop)); + + if (unit[0] == 'i' && unit[1] == 'n') + pixels = 1.0; + else if (unit[0] == 'm' && unit[1] == 'm') + pixels = 25.4; + else if (unit[0] == 'c' && unit[1] == 'm') + pixels = 2.54; + else + pixels = 0; + if (pixels > 0) + { + double ppi; + if ((ppi = NUMVAL (Vdisplay_pixels_per_inch), ppi > 0) + || (CONSP (Vdisplay_pixels_per_inch) + && (ppi = (width_p + ? NUMVAL (XCAR (Vdisplay_pixels_per_inch)) + : NUMVAL (XCDR (Vdisplay_pixels_per_inch))), + ppi > 0))) + return OK_PIXELS (ppi / pixels); + + return 0; + } + } + +#ifdef HAVE_WINDOW_SYSTEM + if (EQ (prop, Qheight)) + return OK_PIXELS (font ? FONT_HEIGHT ((XFontStruct *)font) : FRAME_LINE_HEIGHT (it->f)); + if (EQ (prop, Qwidth)) + return OK_PIXELS (font ? FONT_WIDTH ((XFontStruct *)font) : FRAME_COLUMN_WIDTH (it->f)); +#else + if (EQ (prop, Qheight) || EQ (prop, Qwidth)) + return OK_PIXELS (1); +#endif + + if (EQ (prop, Qtext)) + return OK_PIXELS (width_p + ? window_box_width (it->w, TEXT_AREA) + : WINDOW_BOX_HEIGHT_NO_MODE_LINE (it->w)); + + if (align_to && *align_to < 0) + { + *res = 0; + if (EQ (prop, Qleft)) + return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA)); + if (EQ (prop, Qright)) + return OK_ALIGN_TO (window_box_right_offset (it->w, TEXT_AREA)); + if (EQ (prop, Qcenter)) + return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA) + + window_box_width (it->w, TEXT_AREA) / 2); + if (EQ (prop, Qleft_fringe)) + return OK_ALIGN_TO (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w) + ? WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (it->w) + : window_box_right_offset (it->w, LEFT_MARGIN_AREA)); + if (EQ (prop, Qright_fringe)) + return OK_ALIGN_TO (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w) + ? window_box_right_offset (it->w, RIGHT_MARGIN_AREA) + : window_box_right_offset (it->w, TEXT_AREA)); + if (EQ (prop, Qleft_margin)) + return OK_ALIGN_TO (window_box_left_offset (it->w, LEFT_MARGIN_AREA)); + if (EQ (prop, Qright_margin)) + return OK_ALIGN_TO (window_box_left_offset (it->w, RIGHT_MARGIN_AREA)); + if (EQ (prop, Qscroll_bar)) + return OK_ALIGN_TO (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (it->w) + ? 0 + : (window_box_right_offset (it->w, RIGHT_MARGIN_AREA) + + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w) + ? WINDOW_RIGHT_FRINGE_WIDTH (it->w) + : 0))); + } + else + { + if (EQ (prop, Qleft_fringe)) + return OK_PIXELS (WINDOW_LEFT_FRINGE_WIDTH (it->w)); + if (EQ (prop, Qright_fringe)) + return OK_PIXELS (WINDOW_RIGHT_FRINGE_WIDTH (it->w)); + if (EQ (prop, Qleft_margin)) + return OK_PIXELS (WINDOW_LEFT_MARGIN_WIDTH (it->w)); + if (EQ (prop, Qright_margin)) + return OK_PIXELS (WINDOW_RIGHT_MARGIN_WIDTH (it->w)); + if (EQ (prop, Qscroll_bar)) + return OK_PIXELS (WINDOW_SCROLL_BAR_AREA_WIDTH (it->w)); + } + + prop = Fbuffer_local_value (prop, it->w->buffer); + } + + if (INTEGERP (prop) || FLOATP (prop)) + { + int base_unit = (width_p + ? FRAME_COLUMN_WIDTH (it->f) + : FRAME_LINE_HEIGHT (it->f)); + return OK_PIXELS (XFLOATINT (prop) * base_unit); + } + + if (CONSP (prop)) + { + Lisp_Object car = XCAR (prop); + Lisp_Object cdr = XCDR (prop); + + if (SYMBOLP (car)) + { +#ifdef HAVE_WINDOW_SYSTEM + if (valid_image_p (prop)) + { + int id = lookup_image (it->f, prop); + struct image *img = IMAGE_FROM_ID (it->f, id); + + return OK_PIXELS (width_p ? img->width : img->height); + } +#endif + if (EQ (car, Qplus) || EQ (car, Qminus)) + { + int first = 1; + double px; + + pixels = 0; + while (CONSP (cdr)) + { + if (!calc_pixel_width_or_height (&px, it, XCAR (cdr), + font, width_p, align_to)) + return 0; + if (first) + pixels = (EQ (car, Qplus) ? px : -px), first = 0; + else + pixels += px; + cdr = XCDR (cdr); + } + if (EQ (car, Qminus)) + pixels = -pixels; + return OK_PIXELS (pixels); + } + + car = Fbuffer_local_value (car, it->w->buffer); + } + + if (INTEGERP (car) || FLOATP (car)) + { + double fact; + pixels = XFLOATINT (car); + if (NILP (cdr)) + return OK_PIXELS (pixels); + if (calc_pixel_width_or_height (&fact, it, cdr, + font, width_p, align_to)) + return OK_PIXELS (pixels * fact); + return 0; + } + + return 0; + } + + return 0; +} + /*********************************************************************** Glyph Display @@ -17573,6 +18130,8 @@ append_glyph (it) glyph->charpos = CHARPOS (it->position); glyph->object = it->object; glyph->pixel_width = it->pixel_width; + glyph->ascent = it->ascent; + glyph->descent = it->descent; glyph->voffset = it->voffset; glyph->type = CHAR_GLYPH; glyph->multibyte_p = it->multibyte_p; @@ -17607,6 +18166,8 @@ append_composite_glyph (it) glyph->charpos = CHARPOS (it->position); glyph->object = it->object; glyph->pixel_width = it->pixel_width; + glyph->ascent = it->ascent; + glyph->descent = it->descent; glyph->voffset = it->voffset; glyph->type = COMPOSITE_GLYPH; glyph->multibyte_p = it->multibyte_p; @@ -17655,21 +18216,44 @@ produce_image_glyph (it) { struct image *img; struct face *face; + int face_ascent, glyph_ascent; xassert (it->what == IT_IMAGE); face = FACE_FROM_ID (it->f, it->face_id); + xassert (face); + /* Make sure X resources of the face is loaded. */ + PREPARE_FACE_FOR_DISPLAY (it->f, face); + + if (it->image_id < 0) + { + /* Fringe bitmap. */ + it->ascent = it->phys_ascent = 0; + it->descent = it->phys_descent = 0; + it->pixel_width = 0; + it->nglyphs = 0; + return; + } + img = IMAGE_FROM_ID (it->f, it->image_id); xassert (img); - - /* Make sure X resources of the face and image are loaded. */ - PREPARE_FACE_FOR_DISPLAY (it->f, face); + /* Make sure X resources of the image is loaded. */ prepare_image_for_display (it->f, img); - it->ascent = it->phys_ascent = image_ascent (img, face); + it->ascent = it->phys_ascent = glyph_ascent = image_ascent (img, face); it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent; it->pixel_width = img->width + 2 * img->hmargin; + /* It's quite possible for images to have an ascent greater than + their height, so don't get confused in that case. */ + if (it->descent < 0) + it->descent = 0; + + /* If this glyph is alone on the last line, adjust it.ascent to minimum row ascent. */ + face_ascent = face->font ? FONT_BASE (face->font) : FRAME_BASELINE_OFFSET (it->f); + if (face_ascent > it->ascent) + it->ascent = it->phys_ascent = face_ascent; + it->nglyphs = 1; if (face->box != FACE_NO_BOX) @@ -17699,6 +18283,8 @@ produce_image_glyph (it) glyph->charpos = CHARPOS (it->position); glyph->object = it->object; glyph->pixel_width = it->pixel_width; + glyph->ascent = glyph_ascent; + glyph->descent = it->descent; glyph->voffset = it->voffset; glyph->type = IMAGE_GLYPH; glyph->multibyte_p = it->multibyte_p; @@ -17718,20 +18304,19 @@ produce_image_glyph (it) /* Append a stretch glyph to IT->glyph_row. OBJECT is the source of the glyph, WIDTH and HEIGHT are the width and height of the - stretch. ASCENT is the percentage/100 of HEIGHT to use for the - ascent of the glyph (0 <= ASCENT <= 1). */ + stretch. ASCENT is the ascent of the glyph (0 <= ASCENT <= HEIGHT). */ static void append_stretch_glyph (it, object, width, height, ascent) struct it *it; Lisp_Object object; int width, height; - double ascent; + int ascent; { struct glyph *glyph; enum glyph_row_area area = it->area; - xassert (ascent >= 0 && ascent <= 1); + xassert (ascent >= 0 && ascent <= height); glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area]; if (glyph < it->glyph_row->glyphs[area + 1]) @@ -17739,6 +18324,8 @@ append_stretch_glyph (it, object, width, height, ascent) glyph->charpos = CHARPOS (it->position); glyph->object = object; glyph->pixel_width = width; + glyph->ascent = ascent; + glyph->descent = height - ascent; glyph->voffset = it->voffset; glyph->type = STRETCH_GLYPH; glyph->multibyte_p = it->multibyte_p; @@ -17748,7 +18335,7 @@ append_stretch_glyph (it, object, width, height, ascent) glyph->padding_p = 0; glyph->glyph_not_available_p = 0; glyph->face_id = it->face_id; - glyph->u.stretch.ascent = height * ascent; + glyph->u.stretch.ascent = ascent; glyph->u.stretch.height = height; glyph->font_type = FONT_TYPE_UNKNOWN; ++it->glyph_row->used[area]; @@ -17787,20 +18374,16 @@ append_stretch_glyph (it, object, width, height, ascent) of the stretch should be used for the ascent of the stretch. ASCENT must be in the range 0 <= ASCENT <= 100. */ -#define NUMVAL(X) \ - ((INTEGERP (X) || FLOATP (X)) \ - ? XFLOATINT (X) \ - : - 1) - - static void produce_stretch_glyph (it) struct it *it; { - /* (space :width WIDTH :height HEIGHT. */ + /* (space :width WIDTH :height HEIGHT ...) */ Lisp_Object prop, plist; - int width = 0, height = 0; - double ascent = 0; + int width = 0, height = 0, align_to = -1; + int zero_width_ok_p = 0, zero_height_ok_p = 0; + int ascent = 0; + double tem; struct face *face = FACE_FROM_ID (it->f, it->face_id); XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f); @@ -17811,10 +18394,13 @@ produce_stretch_glyph (it) plist = XCDR (it->object); /* Compute the width of the stretch. */ - if (prop = Fplist_get (plist, QCwidth), - NUMVAL (prop) > 0) - /* Absolute width `:width WIDTH' specified and valid. */ - width = NUMVAL (prop) * FRAME_COLUMN_WIDTH (it->f); + if ((prop = Fplist_get (plist, QCwidth), !NILP (prop)) + && calc_pixel_width_or_height (&tem, it, prop, font, 1, 0)) + { + /* Absolute width `:width WIDTH' specified and valid. */ + zero_width_ok_p = 1; + width = (int)tem; + } else if (prop = Fplist_get (plist, QCrelative_width), NUMVAL (prop) > 0) { @@ -17839,38 +18425,54 @@ produce_stretch_glyph (it) x_produce_glyphs (&it2); width = NUMVAL (prop) * it2.pixel_width; } - else if (prop = Fplist_get (plist, QCalign_to), - NUMVAL (prop) > 0) - width = NUMVAL (prop) * FRAME_COLUMN_WIDTH (it->f) - it->current_x; + else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop)) + && calc_pixel_width_or_height (&tem, it, prop, font, 1, &align_to)) + { + if (it->glyph_row == NULL || !it->glyph_row->mode_line_p) + align_to = (align_to < 0 + ? 0 + : align_to - window_box_left_offset (it->w, TEXT_AREA)); + else if (align_to < 0) + align_to = window_box_left_offset (it->w, TEXT_AREA); + width = max (0, (int)tem + align_to - it->current_x); + zero_width_ok_p = 1; + } else /* Nothing specified -> width defaults to canonical char width. */ width = FRAME_COLUMN_WIDTH (it->f); + if (width <= 0 && (width < 0 || !zero_width_ok_p)) + width = 1; + /* Compute height. */ - if (prop = Fplist_get (plist, QCheight), - NUMVAL (prop) > 0) - height = NUMVAL (prop) * FRAME_LINE_HEIGHT (it->f); + if ((prop = Fplist_get (plist, QCheight), !NILP (prop)) + && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0)) + { + height = (int)tem; + zero_height_ok_p = 1; + } else if (prop = Fplist_get (plist, QCrelative_height), NUMVAL (prop) > 0) height = FONT_HEIGHT (font) * NUMVAL (prop); else height = FONT_HEIGHT (font); + if (height <= 0 && (height < 0 || !zero_height_ok_p)) + height = 1; + /* Compute percentage of height used for ascent. If `:ascent ASCENT' is present and valid, use that. Otherwise, derive the ascent from the font in use. */ if (prop = Fplist_get (plist, QCascent), NUMVAL (prop) > 0 && NUMVAL (prop) <= 100) - ascent = NUMVAL (prop) / 100.0; + ascent = height * NUMVAL (prop) / 100.0; + else if (!NILP (prop) + && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0)) + ascent = min (max (0, (int)tem), height); else - ascent = (double) FONT_BASE (font) / FONT_HEIGHT (font); + ascent = (height * FONT_BASE (font)) / FONT_HEIGHT (font); - if (width <= 0) - width = 1; - if (height <= 0) - height = 1; - - if (it->glyph_row) + if (width > 0 && height > 0 && it->glyph_row) { Lisp_Object object = it->stack[it->sp - 1].string; if (!STRINGP (object)) @@ -17879,11 +18481,11 @@ produce_stretch_glyph (it) } it->pixel_width = width; - it->ascent = it->phys_ascent = height * ascent; + it->ascent = it->phys_ascent = ascent; it->descent = it->phys_descent = height - it->ascent; - it->nglyphs = 1; + it->nglyphs = width > 0 && height > 0 ? 1 : 0; - if (face->box != FACE_NO_BOX) + if (width > 0 && height > 0 && face->box != FACE_NO_BOX) { if (face->box_line_width > 0) { @@ -18038,8 +18640,8 @@ x_produce_glyphs (it) { /* Translate a space with a `space-width' property into a stretch glyph. */ - double ascent = (double) FONT_BASE (font) - / FONT_HEIGHT (font); + int ascent = (((it->ascent + it->descent) * FONT_BASE (font)) + / FONT_HEIGHT (font)); append_stretch_glyph (it, it->object, it->pixel_width, it->ascent + it->descent, ascent); } @@ -18087,9 +18689,8 @@ x_produce_glyphs (it) if (it->glyph_row) { - double ascent = (double) it->ascent / (it->ascent + it->descent); append_stretch_glyph (it, it->object, it->pixel_width, - it->ascent + it->descent, ascent); + it->ascent + it->descent, it->ascent); } } else @@ -18673,7 +19274,7 @@ x_clear_end_of_line (to_x) ARG. If type is BAR_CURSOR, return in *WIDTH the specified width of the bar cursor. */ -enum text_cursor_kinds +static enum text_cursor_kinds get_specified_cursor_type (arg, width) Lisp_Object arg; int *width; @@ -18764,9 +19365,10 @@ set_frame_cursor_types (f, arg) setting of cursor-type. If explicitly marked off, draw no cursor. In all other cases, we want a hollow box cursor. */ -enum text_cursor_kinds -get_window_cursor_type (w, width, active_cursor) +static enum text_cursor_kinds +get_window_cursor_type (w, glyph, width, active_cursor) struct window *w; + struct glyph *glyph; int *width; int *active_cursor; { @@ -18830,7 +19432,13 @@ get_window_cursor_type (w, width, active_cursor) /* Use normal cursor if not blinked off. */ if (!w->cursor_off_p) - return cursor_type; + { + if (glyph != NULL && glyph->type == IMAGE_GLYPH) { + if (cursor_type == FILLED_BOX_CURSOR) + cursor_type = HOLLOW_BOX_CURSOR; + } + return cursor_type; + } /* Cursor is blinked off, so determine how to "toggle" it. */ @@ -18845,6 +19453,11 @@ get_window_cursor_type (w, width, active_cursor) return FRAME_BLINK_OFF_CURSOR (f); } +#if 0 + /* Some people liked having a permanently visible blinking cursor, + while others had very strong opinions against it. So it was + decided to remove it. KFS 2003-09-03 */ + /* Finally perform built-in cursor blinking: filled box <-> hollow box wide [h]bar <-> narrow [h]bar @@ -18859,6 +19472,7 @@ get_window_cursor_type (w, width, active_cursor) *width = 1; return cursor_type; } +#endif return NO_CURSOR; } @@ -18879,36 +19493,53 @@ notice_overwritten_cursor (w, area, x0, x1, y0, y1) enum glyph_row_area area; int x0, y0, x1, y1; { - if (area == TEXT_AREA && w->phys_cursor_on_p) - { - int cx0 = w->phys_cursor.x; - int cx1 = cx0 + w->phys_cursor_width; - int cy0 = w->phys_cursor.y; - int cy1 = cy0 + w->phys_cursor_height; + int cx0, cx1, cy0, cy1; + struct glyph_row *row; - if (x0 <= cx0 && (x1 < 0 || x1 >= cx1)) - { - /* The cursor image will be completely removed from the - screen if the output area intersects the cursor area in - y-direction. When we draw in [y0 y1[, and some part of - the cursor is at y < y0, that part must have been drawn - before. When scrolling, the cursor is erased before - actually scrolling, so we don't come here. When not - scrolling, the rows above the old cursor row must have - changed, and in this case these rows must have written - over the cursor image. + if (!w->phys_cursor_on_p) + return; + if (area != TEXT_AREA) + return; - Likewise if part of the cursor is below y1, with the - exception of the cursor being in the first blank row at - the buffer and window end because update_text_area - doesn't draw that row. (Except when it does, but - that's handled in update_text_area.) */ + row = w->current_matrix->rows + w->phys_cursor.vpos; + if (!row->displays_text_p) + return; - if (((y0 >= cy0 && y0 < cy1) || (y1 > cy0 && y1 < cy1)) - && w->current_matrix->rows[w->phys_cursor.vpos].displays_text_p) - w->phys_cursor_on_p = 0; - } + if (row->cursor_in_fringe_p) + { + row->cursor_in_fringe_p = 0; + draw_fringe_bitmap (w, row, 0); + w->phys_cursor_on_p = 0; + return; } + + cx0 = w->phys_cursor.x; + cx1 = cx0 + w->phys_cursor_width; + if (x0 > cx0 || (x1 >= 0 && x1 < cx1)) + return; + + /* The cursor image will be completely removed from the + screen if the output area intersects the cursor area in + y-direction. When we draw in [y0 y1[, and some part of + the cursor is at y < y0, that part must have been drawn + before. When scrolling, the cursor is erased before + actually scrolling, so we don't come here. When not + scrolling, the rows above the old cursor row must have + changed, and in this case these rows must have written + over the cursor image. + + Likewise if part of the cursor is below y1, with the + exception of the cursor being in the first blank row at + the buffer and window end because update_text_area + doesn't draw that row. (Except when it does, but + that's handled in update_text_area.) */ + + cy0 = w->phys_cursor.y; + cy1 = cy0 + w->phys_cursor_height; + if ((y0 < cy0 || y0 >= cy1) && (y1 <= cy0 || y1 >= cy1)) + return; + + w->phys_cursor_on_p = 0; } #endif /* HAVE_WINDOW_SYSTEM */ @@ -19043,6 +19674,14 @@ erase_phys_cursor (w) if (cursor_row->visible_height <= 0) goto mark_cursor_off; + /* If cursor is in the fringe, erase by drawing actual bitmap there. */ + if (cursor_row->cursor_in_fringe_p) + { + cursor_row->cursor_in_fringe_p = 0; + draw_fringe_bitmap (w, cursor_row, 0); + goto mark_cursor_off; + } + /* This can happen when the new row is shorter than the old one. In this case, either draw_glyphs or clear_end_of_line should have cleared the cursor. Note that we wouldn't be @@ -19111,8 +19750,8 @@ display_and_set_cursor (w, on, hpos, vpos, x, y) int new_cursor_type; int new_cursor_width; int active_cursor; - struct glyph_matrix *current_glyphs; struct glyph_row *glyph_row; + struct glyph *glyph; /* This is pointless on invisible frames, and dangerous on garbaged windows and frames; in the latter case, the frame or window may @@ -19128,9 +19767,7 @@ display_and_set_cursor (w, on, hpos, vpos, x, y) if (!on && !w->phys_cursor_on_p) return; - current_glyphs = w->current_matrix; - glyph_row = MATRIX_ROW (current_glyphs, vpos); - + glyph_row = MATRIX_ROW (w->current_matrix, vpos); /* If cursor row is not enabled, we don't really know where to display the cursor. */ if (!glyph_row->enabled_p) @@ -19139,10 +19776,16 @@ display_and_set_cursor (w, on, hpos, vpos, x, y) return; } + glyph = NULL; + if (!glyph_row->exact_window_width_line_p + || hpos < glyph_row->used[TEXT_AREA]) + glyph = glyph_row->glyphs[TEXT_AREA] + hpos; + xassert (interrupt_input_blocked); /* Set new_cursor_type to the cursor we want to be displayed. */ - new_cursor_type = get_window_cursor_type (w, &new_cursor_width, &active_cursor); + new_cursor_type = get_window_cursor_type (w, glyph, + &new_cursor_width, &active_cursor); /* If cursor is currently being shown and we don't want it to be or it is in the wrong place, or the cursor type is not what we want, @@ -19339,7 +19982,7 @@ clear_mouse_face (dpyinfo) { int cleared = 0; - if (!NILP (dpyinfo->mouse_face_window)) + if (!dpyinfo->mouse_face_hidden && !NILP (dpyinfo->mouse_face_window)) { show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT); cleared = 1; @@ -19416,7 +20059,7 @@ fast_find_position (w, charpos, hpos, vpos, x, y, stop) if (charpos < MATRIX_ROW_START_CHARPOS (first)) { *x = *y = *hpos = *vpos = 0; - return 0; + return 1; } else { @@ -19456,7 +20099,7 @@ fast_find_position (w, charpos, hpos, vpos, x, y, stop) } *hpos = glyph - row->glyphs[TEXT_AREA]; - return past_end; + return !past_end; } #else /* not 1 */ @@ -19642,6 +20285,187 @@ fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p) } +/* See if position X, Y is within a hot-spot of an image. */ + +static int +on_hot_spot_p (hot_spot, x, y) + Lisp_Object hot_spot; + int x, y; +{ + if (!CONSP (hot_spot)) + return 0; + + if (EQ (XCAR (hot_spot), Qrect)) + { + /* CDR is (Top-Left . Bottom-Right) = ((x0 . y0) . (x1 . y1)) */ + Lisp_Object rect = XCDR (hot_spot); + Lisp_Object tem; + if (!CONSP (rect)) + return 0; + if (!CONSP (XCAR (rect))) + return 0; + if (!CONSP (XCDR (rect))) + return 0; + if (!(tem = XCAR (XCAR (rect)), INTEGERP (tem) && x >= XINT (tem))) + return 0; + if (!(tem = XCDR (XCAR (rect)), INTEGERP (tem) && y >= XINT (tem))) + return 0; + if (!(tem = XCAR (XCDR (rect)), INTEGERP (tem) && x <= XINT (tem))) + return 0; + if (!(tem = XCDR (XCDR (rect)), INTEGERP (tem) && y <= XINT (tem))) + return 0; + return 1; + } + else if (EQ (XCAR (hot_spot), Qcircle)) + { + /* CDR is (Center . Radius) = ((x0 . y0) . r) */ + Lisp_Object circ = XCDR (hot_spot); + Lisp_Object lr, lx0, ly0; + if (CONSP (circ) + && CONSP (XCAR (circ)) + && (lr = XCDR (circ), INTEGERP (lr) || FLOATP (lr)) + && (lx0 = XCAR (XCAR (circ)), INTEGERP (lx0)) + && (ly0 = XCDR (XCAR (circ)), INTEGERP (ly0))) + { + double r = XFLOATINT (lr); + double dx = XINT (lx0) - x; + double dy = XINT (ly0) - y; + return (dx * dx + dy * dy <= r * r); + } + } + else if (EQ (XCAR (hot_spot), Qpoly)) + { + /* CDR is [x0 y0 x1 y1 x2 y2 ...x(n-1) y(n-1)] */ + if (VECTORP (XCDR (hot_spot))) + { + struct Lisp_Vector *v = XVECTOR (XCDR (hot_spot)); + Lisp_Object *poly = v->contents; + int n = v->size; + int i; + int inside = 0; + Lisp_Object lx, ly; + int x0, y0; + + /* Need an even number of coordinates, and at least 3 edges. */ + if (n < 6 || n & 1) + return 0; + + /* Count edge segments intersecting line from (X,Y) to (X,infinity). + If count is odd, we are inside polygon. Pixels on edges + may or may not be included depending on actual geometry of the + polygon. */ + if ((lx = poly[n-2], !INTEGERP (lx)) + || (ly = poly[n-1], !INTEGERP (lx))) + return 0; + x0 = XINT (lx), y0 = XINT (ly); + for (i = 0; i < n; i += 2) + { + int x1 = x0, y1 = y0; + if ((lx = poly[i], !INTEGERP (lx)) + || (ly = poly[i+1], !INTEGERP (ly))) + return 0; + x0 = XINT (lx), y0 = XINT (ly); + + /* Does this segment cross the X line? */ + if (x0 >= x) + { + if (x1 >= x) + continue; + } + else if (x1 < x) + continue; + if (y > y0 && y > y1) + continue; + if (y < y0 + ((y1 - y0) * (x - x0)) / (x1 - x0)) + inside = !inside; + } + return inside; + } + } + else + return 0; +} + +Lisp_Object +find_hot_spot (map, x, y) + Lisp_Object map; + int x, y; +{ + while (CONSP (map)) + { + if (CONSP (XCAR (map)) + && on_hot_spot_p (XCAR (XCAR (map)), x, y)) + return XCAR (map); + map = XCDR (map); + } + + return Qnil; +} + +DEFUN ("lookup-image-map", Flookup_image_map, Slookup_image_map, + 3, 3, 0, + doc: /* Lookup in image map MAP coordinates X and Y. +An image map is an alist where each element has the format (AREA ID PLIST). +An AREA is specified as either a rectangle, a circle, or a polygon: +A rectangle is a cons (rect . ((x0 . y0) . (x1 . y1))) specifying the +pixel coordinates of the upper left and bottom right corners. +A circle is a cons (circle . ((x0 . y0) . r)) specifying the center +and the radius of the circle; r may be a float or integer. +A polygon is a cons (poly . [x0 y0 x1 y1 ...]) where each pair in the +vector describes one corner in the polygon. +Returns the alist element for the first matching AREA in MAP. */) + (map, x, y) + Lisp_Object map; + Lisp_Object x, y; +{ + int ix, iy; + if (NILP (map)) + return Qnil; + + CHECK_NUMBER (x); + CHECK_NUMBER (y); + + return find_hot_spot (map, XINT (x), XINT (y)); +} + + +/* Display frame CURSOR, optionally using shape defined by POINTER. */ +static void +define_frame_cursor1 (f, cursor, pointer) + struct frame *f; + Cursor cursor; + Lisp_Object pointer; +{ + if (!NILP (pointer)) + { + if (EQ (pointer, Qarrow)) + cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + else if (EQ (pointer, Qhand)) + cursor = FRAME_X_OUTPUT (f)->hand_cursor; + else if (EQ (pointer, Qtext)) + cursor = FRAME_X_OUTPUT (f)->text_cursor; + else if (EQ (pointer, intern ("hdrag"))) + cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor; +#ifdef HAVE_X_WINDOWS + else if (EQ (pointer, intern ("vdrag"))) + cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor; +#endif + else if (EQ (pointer, intern ("hourglass"))) + cursor = FRAME_X_OUTPUT (f)->hourglass_cursor; + else if (EQ (pointer, Qmodeline)) + cursor = FRAME_X_OUTPUT (f)->modeline_cursor; + else + cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + } + +#ifndef HAVE_CARBON + if (cursor != No_Cursor) +#else + if (bcmp (&cursor, &No_Cursor, sizeof (Cursor))) +#endif + rif->define_frame_cursor (f, cursor); +} + /* Take proper action when mouse has moved to the mode or header line or marginal area AREA of window W, x-position X and y-position Y. X is relative to the start of the text display area of W, so the @@ -19656,19 +20480,62 @@ note_mode_line_or_margin_highlight (w, x, y, area) { struct frame *f = XFRAME (w->frame); Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); - Cursor cursor = dpyinfo->vertical_scroll_bar_cursor; - int charpos; - Lisp_Object string, help, map, pos; + Cursor cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + Lisp_Object pointer = Qnil; + int charpos, dx, dy, width, height; + Lisp_Object string, object = Qnil; + Lisp_Object pos, help, image; if (area == ON_MODE_LINE || area == ON_HEADER_LINE) - string = mode_line_string (w, x, y, area, &charpos); + string = mode_line_string (w, area, &x, &y, &charpos, + &object, &dx, &dy, &width, &height); else - string = marginal_area_string (w, x, y, area, &charpos); + { + x -= WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w); + string = marginal_area_string (w, area, &x, &y, &charpos, + &object, &dx, &dy, &width, &height); + } + + help = Qnil; + + if (IMAGEP (object)) + { + Lisp_Object image_map, hotspot; + if ((image_map = Fplist_get (XCDR (object), QCmap), + !NILP (image_map)) + && (hotspot = find_hot_spot (image_map, dx, dy), + CONSP (hotspot)) + && (hotspot = XCDR (hotspot), CONSP (hotspot))) + { + Lisp_Object area_id, plist; + + area_id = XCAR (hotspot); + /* Could check AREA_ID to see if we enter/leave this hot-spot. + If so, we could look for mouse-enter, mouse-leave + properties in PLIST (and do something...). */ + if ((plist = XCDR (hotspot), CONSP (plist))) + { + pointer = Fplist_get (plist, Qpointer); + if (NILP (pointer)) + pointer = Qhand; + help = Fplist_get (plist, Qhelp_echo); + if (!NILP (help)) + { + help_echo_string = help; + /* Is this correct? ++kfs */ + XSETWINDOW (help_echo_window, w); + help_echo_object = w->buffer; + help_echo_pos = charpos; + } + } + if (NILP (pointer)) + pointer = Fplist_get (XCDR (object), QCpointer); + } + } if (STRINGP (string)) { pos = make_number (charpos); - /* If we're on a string with `help-echo' text property, arrange for the help to be displayed. This is done by setting the global variable help_echo_string to the help string. */ @@ -19681,15 +20548,22 @@ note_mode_line_or_margin_highlight (w, x, y, area) help_echo_pos = charpos; } + if (NILP (pointer)) + pointer = Fget_text_property (pos, Qpointer, string); + /* Change the mouse pointer according to what is under X/Y. */ - map = Fget_text_property (pos, Qlocal_map, string); - if (!KEYMAPP (map)) - map = Fget_text_property (pos, Qkeymap, string); - if (KEYMAPP (map)) - cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + if (NILP (pointer) && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE))) + { + Lisp_Object map; + map = Fget_text_property (pos, Qlocal_map, string); + if (!KEYMAPP (map)) + map = Fget_text_property (pos, Qkeymap, string); + if (!KEYMAPP (map)) + cursor = dpyinfo->vertical_scroll_bar_cursor; + } } - rif->define_frame_cursor (f, cursor); + define_frame_cursor1 (f, cursor, pointer); } @@ -19709,6 +20583,7 @@ note_mouse_highlight (f, x, y) Lisp_Object window; struct window *w; Cursor cursor = No_Cursor; + Lisp_Object pointer = Qnil; /* Takes precedence over cursor! */ struct buffer *b; /* When a menu is active, don't highlight because this looks odd. */ @@ -19746,7 +20621,6 @@ note_mouse_highlight (f, x, y) return; /* Reset help_echo_string. It will get recomputed below. */ - /* ++KFS: X version didn't do this, but it looks harmless. */ help_echo_string = Qnil; /* Convert to window-relative pixel coordinates. */ @@ -19771,6 +20645,8 @@ note_mouse_highlight (f, x, y) if (part == ON_VERTICAL_BORDER) cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor; + else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE) + cursor = FRAME_X_OUTPUT (f)->nontext_cursor; else cursor = FRAME_X_OUTPUT (f)->text_cursor; @@ -19782,7 +20658,7 @@ note_mouse_highlight (f, x, y) && XFASTINT (w->last_modified) == BUF_MODIFF (b) && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b)) { - int hpos, vpos, pos, i, area; + int hpos, vpos, pos, i, dx, dy, area; struct glyph *glyph; Lisp_Object object; Lisp_Object mouse_face = Qnil, overlay = Qnil, position; @@ -19792,21 +20668,60 @@ note_mouse_highlight (f, x, y) int obegv, ozv, same_region; /* Find the glyph under X/Y. */ - glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0); + glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &dx, &dy, &area); + + /* Look for :pointer property on image. */ + if (glyph != NULL && glyph->type == IMAGE_GLYPH) + { + struct image *img = IMAGE_FROM_ID (f, glyph->u.img_id); + if (img != NULL && IMAGEP (img->spec)) + { + Lisp_Object image_map, hotspot; + if ((image_map = Fplist_get (XCDR (img->spec), QCmap), + !NILP (image_map)) + && (hotspot = find_hot_spot (image_map, dx, dy), + CONSP (hotspot)) + && (hotspot = XCDR (hotspot), CONSP (hotspot))) + { + Lisp_Object area_id, plist; + + area_id = XCAR (hotspot); + /* Could check AREA_ID to see if we enter/leave this hot-spot. + If so, we could look for mouse-enter, mouse-leave + properties in PLIST (and do something...). */ + if ((plist = XCDR (hotspot), CONSP (plist))) + { + pointer = Fplist_get (plist, Qpointer); + if (NILP (pointer)) + pointer = Qhand; + help_echo_string = Fplist_get (plist, Qhelp_echo); + if (!NILP (help_echo_string)) + { + help_echo_window = window; + help_echo_object = glyph->object; + help_echo_pos = glyph->charpos; + } + } + } + if (NILP (pointer)) + pointer = Fplist_get (XCDR (img->spec), QCpointer); + } + } /* Clear mouse face if X/Y not over text. */ if (glyph == NULL || area != TEXT_AREA || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p) { -#if defined (HAVE_NTGUI) - /* ++KFS: Why is this necessary on W32 ? */ - clear_mouse_face (dpyinfo); - cursor = FRAME_X_OUTPUT (f)->nontext_cursor; -#else if (clear_mouse_face (dpyinfo)) cursor = No_Cursor; -#endif + if (NILP (pointer)) + { + if (area != TEXT_AREA) + cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + else + pointer = Vvoid_text_area_pointer; + } goto set_cursor; } @@ -20062,7 +20977,7 @@ note_mouse_highlight (f, x, y) check_help_echo: /* Look for a `help-echo' property. */ - { + if (NILP (help_echo_string)) { Lisp_Object help, overlay; /* Check overlays first. */ @@ -20128,6 +21043,46 @@ note_mouse_highlight (f, x, y) } } + /* Look for a `pointer' property. */ + if (NILP (pointer)) + { + /* Check overlays first. */ + for (i = noverlays - 1; i >= 0 && NILP (pointer); --i) + pointer = Foverlay_get (overlay_vec[i], Qpointer); + + if (NILP (pointer)) + { + Lisp_Object object = glyph->object; + int charpos = glyph->charpos; + + /* Try text properties. */ + if (STRINGP (object) + && charpos >= 0 + && charpos < SCHARS (object)) + { + pointer = Fget_text_property (make_number (charpos), + Qpointer, object); + if (NILP (pointer)) + { + /* If the string itself doesn't specify a pointer, + see if the buffer text ``under'' it does. */ + struct glyph_row *r + = MATRIX_ROW (w->current_matrix, vpos); + int start = MATRIX_ROW_START_CHARPOS (r); + int pos = string_buffer_position (w, object, start); + if (pos > 0) + pointer = Fget_char_property (make_number (pos), + Qpointer, w->buffer); + } + } + else if (BUFFERP (object) + && charpos >= BEGV + && charpos < ZV) + pointer = Fget_text_property (make_number (charpos), + Qpointer, object); + } + } + BEGV = obegv; ZV = ozv; current_buffer = obuf; @@ -20135,12 +21090,7 @@ note_mouse_highlight (f, x, y) set_cursor: -#ifndef HAVE_CARBON - if (cursor != No_Cursor) -#else - if (bcmp (&cursor, &No_Cursor, sizeof (Cursor))) -#endif - rif->define_frame_cursor (f, cursor); + define_frame_cursor1 (f, cursor, pointer); } @@ -20220,9 +21170,9 @@ expose_area (w, row, r, area) AREA. The first glyph of the text area can be partially visible. The first glyphs of other areas cannot. */ start_x = window_box_left_offset (w, area); - if (area == TEXT_AREA) - start_x += row->x; x = start_x; + if (area == TEXT_AREA) + x += row->x; /* Find the first glyph that must be redrawn. */ while (first < end @@ -20328,13 +21278,13 @@ phys_cursor_in_rect_p (w, r) cursor_glyph = get_phys_cursor_glyph (w); if (cursor_glyph) { - /* r is relative to W's box, but w->phys_cursor.x is relative + /* r is relative to W's box, but w->phys_cursor.x is relative to left edge of W's TEXT area. Adjust it. */ cr.x = window_box_left_offset (w, TEXT_AREA) + w->phys_cursor.x; cr.y = w->phys_cursor.y; cr.width = cursor_glyph->pixel_width; cr.height = w->phys_cursor_height; - /* ++KFS: W32 version used W32-specific IntersectRect here, but + /* ++KFS: W32 version used W32-specific IntersectRect here, but I assume the effect is the same -- and this is portable. */ return x_intersect_rectangles (&cr, r, &result); } @@ -20352,7 +21302,7 @@ x_draw_vertical_border (w) struct window *w; { /* We could do better, if we knew what type of scroll-bar the adjacent - windows (on either side) have... But we don't :-( + windows (on either side) have... But we don't :-( However, I think this works ok. ++KFS 2003-04-25 */ /* Redraw borders between horizontally adjacent windows. Don't @@ -20736,6 +21686,7 @@ syms_of_xdisp () #endif #ifdef HAVE_WINDOW_SYSTEM defsubr (&Stool_bar_lines_needed); + defsubr (&Slookup_image_map); #endif defsubr (&Sformat_mode_line); @@ -20769,16 +21720,16 @@ syms_of_xdisp () staticpro (&Qspace); Qmargin = intern ("margin"); staticpro (&Qmargin); + Qpointer = intern ("pointer"); + staticpro (&Qpointer); Qleft_margin = intern ("left-margin"); staticpro (&Qleft_margin); Qright_margin = intern ("right-margin"); staticpro (&Qright_margin); - Qalign_to = intern ("align-to"); - staticpro (&Qalign_to); + Qcenter = intern ("center"); + staticpro (&Qcenter); QCalign_to = intern (":align-to"); staticpro (&QCalign_to); - Qrelative_width = intern ("relative-width"); - staticpro (&Qrelative_width); QCrelative_width = intern (":relative-width"); staticpro (&QCrelative_width); QCrelative_height = intern (":relative-height"); @@ -20797,6 +21748,16 @@ syms_of_xdisp () staticpro (&Qtrailing_whitespace); Qimage = intern ("image"); staticpro (&Qimage); + QCmap = intern (":map"); + staticpro (&QCmap); + QCpointer = intern (":pointer"); + staticpro (&QCpointer); + Qrect = intern ("rect"); + staticpro (&Qrect); + Qcircle = intern ("circle"); + staticpro (&Qcircle); + Qpoly = intern ("poly"); + staticpro (&Qpoly); Qmessage_truncate_lines = intern ("message-truncate-lines"); staticpro (&Qmessage_truncate_lines); Qcursor_in_non_selected_windows = intern ("cursor-in-non-selected-windows"); @@ -20821,18 +21782,31 @@ syms_of_xdisp () staticpro (&Qbox); Qhollow = intern ("hollow"); staticpro (&Qhollow); + Qhand = intern ("hand"); + staticpro (&Qhand); + Qarrow = intern ("arrow"); + staticpro (&Qarrow); + Qtext = intern ("text"); + staticpro (&Qtext); Qrisky_local_variable = intern ("risky-local-variable"); staticpro (&Qrisky_local_variable); Qinhibit_free_realized_faces = intern ("inhibit-free-realized-faces"); staticpro (&Qinhibit_free_realized_faces); - list_of_error = Fcons (intern ("error"), Qnil); + list_of_error = Fcons (Fcons (intern ("error"), + Fcons (intern ("void-variable"), Qnil)), + Qnil); staticpro (&list_of_error); - last_arrow_position = Qnil; - last_arrow_string = Qnil; - staticpro (&last_arrow_position); - staticpro (&last_arrow_string); + Qlast_arrow_position = intern ("last-arrow-position"); + staticpro (&Qlast_arrow_position); + Qlast_arrow_string = intern ("last-arrow-string"); + staticpro (&Qlast_arrow_string); + + Qoverlay_arrow_string = intern ("overlay-arrow-string"); + staticpro (&Qoverlay_arrow_string); + Qoverlay_arrow_bitmap = intern ("overlay-arrow-bitmap"); + staticpro (&Qoverlay_arrow_bitmap); echo_buffer[0] = echo_buffer[1] = Qnil; staticpro (&echo_buffer[0]); @@ -20870,10 +21844,16 @@ wide as that tab on the display. */); #endif DEFVAR_LISP ("show-trailing-whitespace", &Vshow_trailing_whitespace, - doc: /* Non-nil means highlight trailing whitespace. + doc: /* *Non-nil means highlight trailing whitespace. The face used for trailing whitespace is `trailing-whitespace'. */); Vshow_trailing_whitespace = Qnil; + DEFVAR_LISP ("void-text-area-pointer", &Vvoid_text_area_pointer, + doc: /* *The pointer shape to show in void text areas. +Nil means to show the text pointer. Other options are `arrow', `text', +`hand', `vdrag', `hdrag', `modeline', and `hourglass'. */); + Vvoid_text_area_pointer = Qarrow; + DEFVAR_LISP ("inhibit-redisplay", &Vinhibit_redisplay, doc: /* Non-nil means don't actually do any redisplay. This is used for internal purposes. */); @@ -20890,9 +21870,17 @@ See also `overlay-arrow-string'. */); Voverlay_arrow_position = Qnil; DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string, - doc: /* String to display as an arrow. See also `overlay-arrow-position'. */); + doc: /* String to display as an arrow in non-window frames. +See also `overlay-arrow-position'. */); Voverlay_arrow_string = Qnil; + DEFVAR_LISP ("overlay-arrow-variable-list", &Voverlay_arrow_variable_list, + doc: /* List of variables (symbols) which hold markers for overlay arrows. +The symbols on this list are examined during redisplay to determine +where to display overlay arrows. */); + Voverlay_arrow_variable_list + = Fcons (intern ("overlay-arrow-position"), Qnil); + DEFVAR_INT ("scroll-step", &scroll_step, doc: /* *The number of lines to try scrolling a window by when point moves out. If that fails to bring point back on frame, point is centered instead. @@ -20912,6 +21900,11 @@ Recenter the window whenever point gets within this many lines of the top or bottom of the window. */); scroll_margin = 0; + DEFVAR_LISP ("display-pixels-per-inch", &Vdisplay_pixels_per_inch, + doc: /* Pixels per inch on current display. +Value is a number or a cons (WIDTH-DPI . HEIGHT-DPI). */); + Vdisplay_pixels_per_inch = make_float (72.0); + #if GLYPH_DEBUG DEFVAR_INT ("debug-end-pos", &debug_end_pos, doc: /* Don't ask. */); #endif @@ -20956,6 +21949,7 @@ This variable is not guaranteed to be accurate except while processing This variable has the same structure as `mode-line-format' (which see), and is used only on frames for which no explicit name has been set \(see `modify-frame-parameters'). */); + DEFVAR_LISP ("icon-title-format", &Vicon_title_format, doc: /* Template for displaying the title bar of an iconified frame. \(Assuming the window manager supports this feature.) @@ -21189,3 +22183,5 @@ init_xdisp () } +/* arch-tag: eacc864d-bb6a-4b74-894a-1a4399a1358b + (do not change this comment) */ diff --git a/src/xfaces.c b/src/xfaces.c index c588527eaa9..f44b216877f 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -1,5 +1,5 @@ /* xfaces.c -- "Face" primitives. - Copyright (C) 1993, 1994, 1998, 1999, 2000, 2001, 2002, 2003 + Copyright (C) 1993, 1994, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation. This file is part of GNU Emacs. @@ -194,6 +194,7 @@ Boston, MA 02111-1307, USA. */ used to fill in unspecified attributes of the default face. */ #include <config.h> +#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> @@ -264,7 +265,6 @@ Boston, MA 02111-1307, USA. */ #endif /* HAVE_X_WINDOWS */ -#include <stdio.h> #include <ctype.h> #define abs(X) ((X) < 0 ? -(X) : (X)) @@ -1503,15 +1503,19 @@ face_color_supported_p (f, color_name, background_p) XColor not_used; XSETFRAME (frame, f); - return (FRAME_WINDOW_P (f) - ? (!NILP (Fxw_display_color_p (frame)) - || xstricmp (color_name, "black") == 0 - || xstricmp (color_name, "white") == 0 - || (background_p - && face_color_gray_p (f, color_name)) - || (!NILP (Fx_display_grayscale_p (frame)) - && face_color_gray_p (f, color_name))) - : tty_defined_color (f, color_name, ¬_used, 0)); + return +#ifdef HAVE_X_WINDOWS + FRAME_WINDOW_P (f) + ? (!NILP (Fxw_display_color_p (frame)) + || xstricmp (color_name, "black") == 0 + || xstricmp (color_name, "white") == 0 + || (background_p + && face_color_gray_p (f, color_name)) + || (!NILP (Fx_display_grayscale_p (frame)) + && face_color_gray_p (f, color_name))) + : +#endif + tty_defined_color (f, color_name, ¬_used, 0); } @@ -1524,8 +1528,11 @@ If FRAME is nil or omitted, use the selected frame. */) { struct frame *f; - CHECK_FRAME (frame); CHECK_STRING (color); + if (NILP (frame)) + frame = selected_frame; + else + CHECK_FRAME (frame); f = XFRAME (frame); return face_color_gray_p (f, SDATA (color)) ? Qt : Qnil; } @@ -1542,8 +1549,11 @@ COLOR must be a valid color name. */) { struct frame *f; - CHECK_FRAME (frame); CHECK_STRING (color); + if (NILP (frame)) + frame = selected_frame; + else + CHECK_FRAME (frame); f = XFRAME (frame); if (face_color_supported_p (f, SDATA (color), !NILP (background_p))) return Qt; @@ -2613,6 +2623,69 @@ x_face_list_fonts (f, pattern, pfonts, nfonts, try_alternatives_p) } +/* Check if a font matching pattern_offset_t on frame F is available + or not. PATTERN may be a cons (FAMILY . REGISTRY), in which case, + a font name pattern is generated from FAMILY and REGISTRY. */ + +int +face_font_available_p (f, pattern) + struct frame *f; + Lisp_Object pattern; +{ + Lisp_Object fonts; + + if (! STRINGP (pattern)) + { + Lisp_Object family, registry; + char *family_str, *registry_str, *pattern_str; + + CHECK_CONS (pattern); + family = XCAR (pattern); + if (NILP (family)) + family_str = "*"; + else + { + CHECK_STRING (family); + family_str = (char *) SDATA (family); + } + registry = XCDR (pattern); + if (NILP (registry)) + registry_str = "*"; + else + { + CHECK_STRING (registry); + registry_str = (char *) SDATA (registry); + } + + pattern_str = (char *) alloca (strlen (family_str) + + strlen (registry_str) + + 10); + strcpy (pattern_str, index (family_str, '-') ? "-" : "-*-"); + strcat (pattern_str, family_str); + strcat (pattern_str, "-*-"); + strcat (pattern_str, registry_str); + if (!index (registry_str, '-')) + { + if (registry_str[strlen (registry_str) - 1] == '*') + strcat (pattern_str, "-*"); + else + strcat (pattern_str, "*-*"); + } + pattern = build_string (pattern_str); + } + + /* Get the list of fonts matching PATTERN. */ +#ifdef WINDOWSNT + BLOCK_INPUT; + fonts = w32_list_fonts (f, pattern, 0, 1); + UNBLOCK_INPUT; +#else + fonts = x_list_fonts (f, pattern, -1, 1); +#endif + return XINT (Flength (fonts)); +} + + /* Determine fonts matching PATTERN on frame F. Sort resulting fonts using comparison function CMPFN. Value is the number of fonts found. If value is non-zero, *FONTS is set to a vector of @@ -3243,7 +3316,13 @@ lface_fully_specified_p (attrs) for (i = 1; i < LFACE_VECTOR_SIZE; ++i) if (i != LFACE_FONT_INDEX && i != LFACE_INHERIT_INDEX && i != LFACE_AVGWIDTH_INDEX && i != LFACE_FONTSET_INDEX) - if (UNSPECIFIEDP (attrs[i])) + if (UNSPECIFIEDP (attrs[i]) +#ifdef MAC_OS + /* MAC_TODO: No stipple support on Mac OS yet, this index is + always unspecified. */ + && i != LFACE_STIPPLE_INDEX +#endif + ) break; return i == LFACE_VECTOR_SIZE; @@ -5662,12 +5741,19 @@ cache_face (c, face, hash) face->id = i; /* Maybe enlarge C->faces_by_id. */ - if (i == c->used && c->used == c->size) + if (i == c->used) { - int new_size = 2 * c->size; - int sz = new_size * sizeof *c->faces_by_id; - c->faces_by_id = (struct face **) xrealloc (c->faces_by_id, sz); - c->size = new_size; + if (c->used == c->size) + { + int new_size, sz; + new_size = min (2 * c->size, MAX_FACE_ID); + if (new_size == c->size) + abort (); /* Alternatives? ++kfs */ + sz = new_size * sizeof *c->faces_by_id; + c->faces_by_id = (struct face **) xrealloc (c->faces_by_id, sz); + c->size = new_size; + } + c->used++; } #if GLYPH_DEBUG @@ -5686,8 +5772,6 @@ cache_face (c, face, hash) #endif /* GLYPH_DEBUG */ c->faces_by_id[i] = face; - if (i == c->used) - ++c->used; } @@ -6176,6 +6260,18 @@ better_font_p (values, font1, font2, compare_pt_p, avgwidth) return 1; } + if (! compare_pt_p) + { + /* We prefer a real scalable font; i.e. not what autoscaled. */ + int auto_scaled_1 = (font1->numeric[XLFD_POINT_SIZE] == 0 + && font1->numeric[XLFD_RESY] > 0); + int auto_scaled_2 = (font2->numeric[XLFD_POINT_SIZE] == 0 + && font2->numeric[XLFD_RESY] > 0); + + if (auto_scaled_1 != auto_scaled_2) + return auto_scaled_2; + } + return font1->registry_priority < font2->registry_priority; } @@ -6414,7 +6510,10 @@ best_matching_font (f, attrs, fonts, nfonts, width_ratio, needs_overstrike) || better_font_p (specified, fonts + i, best, 0, 0) || (!non_scalable_has_exact_height_p && !better_font_p (specified, best, fonts + i, 0, 0))) - best = fonts + i; + { + non_scalable_has_exact_height_p = 1; + best = fonts + i; + } } if (needs_overstrike) @@ -7918,3 +8017,6 @@ a font of 10 point, we actually use a font of 10 * RESCALE-RATIO point. */); defsubr (&Sx_font_family_list); #endif /* HAVE_WINDOW_SYSTEM */ } + +/* arch-tag: 8a0f7598-5517-408d-9ab3-1da6fcd4c749 + (do not change this comment) */ diff --git a/src/xfns.c b/src/xfns.c index 92ec2aa3352..12df902ae49 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, 97, 98, 99, 2000, 01, 02, 03 + Copyright (C) 1989, 92, 93, 94, 95, 96, 97, 98, 99, 2000,01,02,03,04 Free Software Foundation. This file is part of GNU Emacs. @@ -126,6 +126,14 @@ static Lisp_Object Vmotif_version_string; #endif /* USE_X_TOOLKIT */ +#ifdef USE_GTK + +/* GTK+ version info */ + +static Lisp_Object Vgtk_version_string; + +#endif /* USE_GTK */ + #ifdef HAVE_X11R4 #define MAXREQUEST(dpy) (XMaxRequestSize (dpy)) #else @@ -171,10 +179,6 @@ static int x_in_use; Lisp_Object Vx_no_window_manager; -/* Search path for bitmap files. */ - -Lisp_Object Vx_bitmap_file_path; - /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */ Lisp_Object Vx_pixel_size_width_font_regexp; @@ -182,7 +186,6 @@ Lisp_Object Vx_pixel_size_width_font_regexp; Lisp_Object Qnone; Lisp_Object Qsuppress_icon; Lisp_Object Qundefined_color; -Lisp_Object Qcenter; Lisp_Object Qcompound_text, Qcancel_timer; /* In dispnew.c */ @@ -301,7 +304,7 @@ x_window_to_frame (dpyinfo, wdesc) #ifdef USE_GTK if (f->output_data.x->edit_widget) { - GtkWidget *gwdesc = xg_win_to_widget (wdesc); + GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc); struct x_output *x = f->output_data.x; if (gwdesc != 0 && gwdesc == x->edit_widget) return f; @@ -345,7 +348,7 @@ x_any_window_to_frame (dpyinfo, wdesc) else if (x->widget) { #ifdef USE_GTK - GtkWidget *gwdesc = xg_win_to_widget (wdesc); + GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc); if (gwdesc != 0 && (gwdesc == x->widget || gwdesc == x->edit_widget @@ -397,7 +400,7 @@ x_non_menubar_window_to_frame (dpyinfo, wdesc) else if (x->widget) { #ifdef USE_GTK - GtkWidget *gwdesc = xg_win_to_widget (wdesc); + GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc); if (gwdesc != 0 && (gwdesc == x->widget || gwdesc == x->edit_widget @@ -441,7 +444,7 @@ x_menubar_window_to_frame (dpyinfo, wdesc) #ifdef USE_GTK if (x->menubar_widget) { - GtkWidget *gwdesc = xg_win_to_widget (wdesc); + GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc); int found = 0; BLOCK_INPUT; @@ -487,7 +490,7 @@ x_top_window_to_frame (dpyinfo, wdesc) { /* This frame matches if the window is its topmost widget. */ #ifdef USE_GTK - GtkWidget *gwdesc = xg_win_to_widget (wdesc); + GtkWidget *gwdesc = xg_win_to_widget (dpyinfo->display, wdesc); if (gwdesc == x->widget) return f; #else @@ -513,331 +516,8 @@ x_top_window_to_frame (dpyinfo, wdesc) -/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap - id, which is just an int that this section returns. Bitmaps are - reference counted so they can be shared among frames. - - Bitmap indices are guaranteed to be > 0, so a negative number can - be used to indicate no bitmap. - - If you use x_create_bitmap_from_data, then you must keep track of - the bitmaps yourself. That is, creating a bitmap from the same - data more than once will not be caught. */ - - -/* Functions to access the contents of a bitmap, given an id. */ - -int -x_bitmap_height (f, id) - FRAME_PTR f; - int id; -{ - return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].height; -} - -int -x_bitmap_width (f, id) - FRAME_PTR f; - int id; -{ - return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].width; -} - -int -x_bitmap_pixmap (f, id) - FRAME_PTR f; - int id; -{ - return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap; -} - -int -x_bitmap_mask (f, id) - FRAME_PTR f; - int id; -{ - return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].mask; -} - - -/* Allocate a new bitmap record. Returns index of new record. */ - -static int -x_allocate_bitmap_record (f) - FRAME_PTR f; -{ - struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); - int i; - - if (dpyinfo->bitmaps == NULL) - { - dpyinfo->bitmaps_size = 10; - dpyinfo->bitmaps - = (struct x_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct x_bitmap_record)); - dpyinfo->bitmaps_last = 1; - return 1; - } - - if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size) - return ++dpyinfo->bitmaps_last; - - for (i = 0; i < dpyinfo->bitmaps_size; ++i) - if (dpyinfo->bitmaps[i].refcount == 0) - return i + 1; - - dpyinfo->bitmaps_size *= 2; - dpyinfo->bitmaps - = (struct x_bitmap_record *) xrealloc (dpyinfo->bitmaps, - dpyinfo->bitmaps_size * sizeof (struct x_bitmap_record)); - return ++dpyinfo->bitmaps_last; -} - -/* Add one reference to the reference count of the bitmap with id ID. */ - -void -x_reference_bitmap (f, id) - FRAME_PTR f; - int id; -{ - ++FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].refcount; -} - -/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */ - -int -x_create_bitmap_from_data (f, bits, width, height) - struct frame *f; - char *bits; - unsigned int width, height; -{ - struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); - Pixmap bitmap; - int id; - - bitmap = XCreateBitmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - bits, width, height); - - - - if (! bitmap) - return -1; - - id = x_allocate_bitmap_record (f); - dpyinfo->bitmaps[id - 1].pixmap = bitmap; - dpyinfo->bitmaps[id - 1].have_mask = 0; - dpyinfo->bitmaps[id - 1].file = NULL; - dpyinfo->bitmaps[id - 1].refcount = 1; - dpyinfo->bitmaps[id - 1].depth = 1; - dpyinfo->bitmaps[id - 1].height = height; - dpyinfo->bitmaps[id - 1].width = width; - - return id; -} - -/* Create bitmap from file FILE for frame F. */ - -int -x_create_bitmap_from_file (f, file) - struct frame *f; - Lisp_Object file; -{ - struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); - unsigned int width, height; - Pixmap bitmap; - int xhot, yhot, result, id; - Lisp_Object found; - int fd; - char *filename; - - /* Look for an existing bitmap with the same name. */ - for (id = 0; id < dpyinfo->bitmaps_last; ++id) - { - if (dpyinfo->bitmaps[id].refcount - && dpyinfo->bitmaps[id].file - && !strcmp (dpyinfo->bitmaps[id].file, (char *) SDATA (file))) - { - ++dpyinfo->bitmaps[id].refcount; - return id + 1; - } - } - - /* Search bitmap-file-path for the file, if appropriate. */ - fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil); - if (fd < 0) - return -1; - emacs_close (fd); - - filename = (char *) SDATA (found); - - result = XReadBitmapFile (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - filename, &width, &height, &bitmap, &xhot, &yhot); - if (result != BitmapSuccess) - return -1; - - id = x_allocate_bitmap_record (f); - dpyinfo->bitmaps[id - 1].pixmap = bitmap; - dpyinfo->bitmaps[id - 1].have_mask = 0; - dpyinfo->bitmaps[id - 1].refcount = 1; - dpyinfo->bitmaps[id - 1].file - = (char *) xmalloc (SBYTES (file) + 1); - dpyinfo->bitmaps[id - 1].depth = 1; - dpyinfo->bitmaps[id - 1].height = height; - dpyinfo->bitmaps[id - 1].width = width; - strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file)); - - return id; -} - -/* Remove reference to bitmap with id number ID. */ - -void -x_destroy_bitmap (f, id) - FRAME_PTR f; - int id; -{ - struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); - - if (id > 0) - { - --dpyinfo->bitmaps[id - 1].refcount; - if (dpyinfo->bitmaps[id - 1].refcount == 0) - { - BLOCK_INPUT; - XFreePixmap (FRAME_X_DISPLAY (f), dpyinfo->bitmaps[id - 1].pixmap); - if (dpyinfo->bitmaps[id - 1].have_mask) - XFreePixmap (FRAME_X_DISPLAY (f), dpyinfo->bitmaps[id - 1].mask); - if (dpyinfo->bitmaps[id - 1].file) - { - xfree (dpyinfo->bitmaps[id - 1].file); - dpyinfo->bitmaps[id - 1].file = NULL; - } - UNBLOCK_INPUT; - } - } -} - -/* Free all the bitmaps for the display specified by DPYINFO. */ - -static void -x_destroy_all_bitmaps (dpyinfo) - struct x_display_info *dpyinfo; -{ - int i; - for (i = 0; i < dpyinfo->bitmaps_last; i++) - if (dpyinfo->bitmaps[i].refcount > 0) - { - XFreePixmap (dpyinfo->display, dpyinfo->bitmaps[i].pixmap); - if (dpyinfo->bitmaps[i].have_mask) - XFreePixmap (dpyinfo->display, dpyinfo->bitmaps[i].mask); - if (dpyinfo->bitmaps[i].file) - xfree (dpyinfo->bitmaps[i].file); - } - dpyinfo->bitmaps_last = 0; -} - - - - -/* Useful functions defined in the section - `Image type independent image structures' below. */ - -static unsigned long four_corners_best P_ ((XImage *ximg, unsigned long width, - unsigned long height)); - -static int x_create_x_image_and_pixmap P_ ((struct frame *f, int width, int height, - int depth, XImage **ximg, - Pixmap *pixmap)); - -static void x_destroy_x_image P_ ((XImage *ximg)); - - -/* Create a mask of a bitmap. Note is this not a perfect mask. - It's nicer with some borders in this context */ - -int -x_create_bitmap_mask(f, id) - struct frame *f; - int id; -{ - Pixmap pixmap, mask; - XImage *ximg, *mask_img; - unsigned long width, height; - int result; - unsigned long bg; - unsigned long x, y, xp, xm, yp, ym; - GC gc; - - struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); - - if (!(id > 0)) - return -1; - - pixmap = x_bitmap_pixmap(f, id); - width = x_bitmap_width(f, id); - height = x_bitmap_height(f, id); - - BLOCK_INPUT; - ximg = XGetImage (FRAME_X_DISPLAY (f), pixmap, 0, 0, width, height, - ~0, ZPixmap); - - if (!ximg) - { - UNBLOCK_INPUT; - return -1; - } - - result = x_create_x_image_and_pixmap (f, width, height, 1, &mask_img, &mask); - - UNBLOCK_INPUT; - if (!result) - { - XDestroyImage(ximg); - return -1; - } - - bg = four_corners_best (ximg, width, height); - - for (y = 0; y < ximg->height; ++y) - { - for (x = 0; x < ximg->width; ++x) - { - xp = x != ximg->width - 1 ? x + 1 : 0; - xm = x != 0 ? x - 1 : ximg->width - 1; - yp = y != ximg->height - 1 ? y + 1 : 0; - ym = y != 0 ? y - 1 : ximg->height - 1; - if (XGetPixel (ximg, x, y) == bg - && XGetPixel (ximg, x, yp) == bg - && XGetPixel (ximg, x, ym) == bg - && XGetPixel (ximg, xp, y) == bg - && XGetPixel (ximg, xp, yp) == bg - && XGetPixel (ximg, xp, ym) == bg - && XGetPixel (ximg, xm, y) == bg - && XGetPixel (ximg, xm, yp) == bg - && XGetPixel (ximg, xm, ym) == bg) - XPutPixel (mask_img, x, y, 0); - else - XPutPixel (mask_img, x, y, 1); - } - } - - xassert (interrupt_input_blocked); - gc = XCreateGC (FRAME_X_DISPLAY (f), mask, 0, NULL); - XPutImage (FRAME_X_DISPLAY (f), mask, gc, mask_img, 0, 0, 0, 0, - width, height); - XFreeGC (FRAME_X_DISPLAY (f), gc); - - dpyinfo->bitmaps[id - 1].have_mask = 1; - dpyinfo->bitmaps[id - 1].mask = mask; - - XDestroyImage (ximg); - x_destroy_x_image(mask_img); - - return 0; -} - static Lisp_Object unwind_create_frame P_ ((Lisp_Object)); static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object)); -static void x_disable_image P_ ((struct frame *, struct image *)); void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object)); static void x_set_wait_for_wm P_ ((struct frame *, Lisp_Object, Lisp_Object)); @@ -861,16 +541,6 @@ static Lisp_Object x_default_scroll_bar_color_parameter P_ ((struct frame *, Lisp_Object, char *, char *, int)); -static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object, - Lisp_Object)); -static void init_color_table P_ ((void)); -static void free_color_table P_ ((void)); -static unsigned long *colors_in_color_table P_ ((int *n)); -static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b)); -static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p)); - - - /* Store the screen positions of frame F into XPTR and YPTR. @@ -1092,13 +762,11 @@ x_set_wait_for_wm (f, new_value, old_value) #ifdef USE_GTK -static Lisp_Object x_find_image_file P_ ((Lisp_Object file)); - /* Set icon from FILE for frame F. By using GTK functions the icon may be any format that GdkPixbuf knows about, i.e. not just bitmaps. */ int -xg_set_icon(f, file) +xg_set_icon (f, file) FRAME_PTR f; Lisp_Object file; { @@ -1292,7 +960,6 @@ x_set_mouse_color (f, arg, oldval) hourglass_cursor = XCreateFontCursor (dpy, XC_watch); x_check_errors (dpy, "bad hourglass pointer cursor: %s"); - x_check_errors (dpy, "bad nontext pointer cursor: %s"); if (!NILP (Vx_mode_pointer_shape)) { CHECK_NUMBER (Vx_mode_pointer_shape); @@ -1589,7 +1256,7 @@ x_set_menu_bar_lines (f, value, oldval) Lisp_Object value, oldval; { int nlines; -#ifndef USE_X_TOOLKIT +#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) int olines = FRAME_MENU_BAR_LINES (f); #endif @@ -2429,8 +2096,8 @@ create_frame_xic (f) xic = XCreateIC (xim, XNInputStyle, xic_style, - XNClientWindow, FRAME_X_WINDOW(f), - XNFocusWindow, FRAME_X_WINDOW(f), + XNClientWindow, FRAME_X_WINDOW (f), + XNFocusWindow, FRAME_X_WINDOW (f), XNStatusAttributes, status_attr, XNPreeditAttributes, preedit_attr, NULL); @@ -2521,7 +2188,7 @@ xic_set_statusarea (f) XFree (needed); attr = XVaCreateNestedList (0, XNArea, &area, NULL); - XSetICValues(xic, XNStatusAttributes, attr, NULL); + XSetICValues (xic, XNStatusAttributes, attr, NULL); XFree (attr); } @@ -2641,7 +2308,7 @@ x_window (f, window_prompting, minibuffer_only) { int len; char *tem, shell_position[32]; - Arg al[2]; + Arg al[10]; int ac = 0; int extra_borders = 0; int menubar_size @@ -2693,9 +2360,19 @@ x_window (f, window_prompting, minibuffer_only) (xneg ? '-' : '+'), left, (yneg ? '-' : '+'), top); else - sprintf (shell_position, "=%dx%d", - FRAME_PIXEL_WIDTH (f) + extra_borders, - FRAME_PIXEL_HEIGHT (f) + menubar_size + extra_borders); + { + sprintf (shell_position, "=%dx%d", + FRAME_PIXEL_WIDTH (f) + extra_borders, + FRAME_PIXEL_HEIGHT (f) + menubar_size + extra_borders); + + /* Setting x and y when the position is not specified in + the geometry string will set program position in the WM hints. + If Emacs had just one program position, we could set it in + fallback resources, but since each make-frame call can specify + different program positions, this is easier. */ + XtSetArg (al[ac], XtNx, left); ac++; + XtSetArg (al[ac], XtNy, top); ac++; + } } len = strlen (shell_position) + 1; @@ -2754,7 +2431,7 @@ x_window (f, window_prompting, minibuffer_only) { /* XIM server might require some X events. */ unsigned long fevent = NoEventMask; - XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL); + XGetICValues (FRAME_XIC (f), XNFilterEvents, &fevent, NULL); attributes.event_mask |= fevent; } #endif /* HAVE_X_I18N */ @@ -2800,7 +2477,7 @@ x_window (f) #ifdef HAVE_X_I18N FRAME_XIC (f) = NULL; -if (use_xim) + if (use_xim) { BLOCK_INPUT; create_frame_xic (f); @@ -2808,7 +2485,7 @@ if (use_xim) { /* XIM server might require some X events. */ unsigned long fevent = NoEventMask; - XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL); + XGetICValues (FRAME_XIC (f), XNFilterEvents, &fevent, NULL); if (fevent != NoEventMask) { @@ -2872,7 +2549,7 @@ x_window (f) { /* XIM server might require some X events. */ unsigned long fevent = NoEventMask; - XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL); + XGetICValues (FRAME_XIC (f), XNFilterEvents, &fevent, NULL); attributes.event_mask |= fevent; attribute_mask = CWEventMask; XChangeWindowAttributes (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), @@ -3509,6 +3186,19 @@ This function is an internal primitive--use `make-frame' instead. */) ; } + /* Set the WM leader property. GTK does this itself, so this is not + needed when using GTK. */ + if (dpyinfo->client_leader_window != 0) + { + BLOCK_INPUT; + XChangeProperty (FRAME_X_DISPLAY (f), + FRAME_OUTER_WINDOW (f), + dpyinfo->Xatom_wm_client_leader, + XA_WINDOW, 32, PropModeReplace, + (char *) &dpyinfo->client_leader_window, 1); + UNBLOCK_INPUT; + } + UNGCPRO; /* Make sure windows on this frame appear in calls to next-window @@ -3712,8 +3402,17 @@ If omitted or nil, that stands for the selected frame's display. */) { struct x_display_info *dpyinfo = check_x_display_info (display); - return make_number (DisplayCells (dpyinfo->display, - XScreenNumberOfScreen (dpyinfo->screen))); + int nr_planes = DisplayPlanes (dpyinfo->display, + XScreenNumberOfScreen (dpyinfo->screen)); + + /* Truncate nr_planes to 24 to avoid integer overflow. + Some displays says 32, but only 24 bits are actually significant. + There are only very few and rare video cards that have more than + 24 significant bits. Also 24 bits is more than 16 million colors, + it "should be enough for everyone". */ + if (nr_planes > 24) nr_planes = 24; + + return make_number (1 << nr_planes); } DEFUN ("x-server-max-request-size", Fx_server_max_request_size, @@ -4174,9 +3873,6 @@ If DISPLAY is nil, that stands for the selected frame's display. */) for (i = 0; i < dpyinfo->n_fonts; i++) if (dpyinfo->font_table[i].name) { - if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name) - xfree (dpyinfo->font_table[i].full_name); - xfree (dpyinfo->font_table[i].name); XFreeFont (dpyinfo->display, dpyinfo->font_table[i].font); } @@ -4240,5189 +3936,89 @@ x_sync (f) /*********************************************************************** - Image types - ***********************************************************************/ - -/* Value is the number of elements of vector VECTOR. */ - -#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR)) - -/* List of supported image types. Use define_image_type to add new - types. Use lookup_image_type to find a type for a given symbol. */ - -static struct image_type *image_types; - -/* The symbol `image' which is the car of the lists used to represent - images in Lisp. */ - -extern Lisp_Object Qimage; - -/* The symbol `xbm' which is used as the type symbol for XBM images. */ - -Lisp_Object Qxbm; - -/* Keywords. */ - -extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile; -extern Lisp_Object QCdata, QCtype; -Lisp_Object QCascent, QCmargin, QCrelief; -Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask; -Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask; - -/* Other symbols. */ - -Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic; - -/* Time in seconds after which images should be removed from the cache - if not displayed. */ - -Lisp_Object Vimage_cache_eviction_delay; - -/* Function prototypes. */ - -static void define_image_type P_ ((struct image_type *type)); -static struct image_type *lookup_image_type P_ ((Lisp_Object symbol)); -static void image_error P_ ((char *format, Lisp_Object, Lisp_Object)); -static void x_laplace P_ ((struct frame *, struct image *)); -static void x_emboss P_ ((struct frame *, struct image *)); -static int x_build_heuristic_mask P_ ((struct frame *, struct image *, - Lisp_Object)); - - -/* Define a new image type from TYPE. This adds a copy of TYPE to - image_types and adds the symbol *TYPE->type to Vimage_types. */ - -static void -define_image_type (type) - struct image_type *type; -{ - /* Make a copy of TYPE to avoid a bus error in a dumped Emacs. - The initialized data segment is read-only. */ - struct image_type *p = (struct image_type *) xmalloc (sizeof *p); - bcopy (type, p, sizeof *p); - p->next = image_types; - image_types = p; - Vimage_types = Fcons (*p->type, Vimage_types); -} - - -/* Look up image type SYMBOL, and return a pointer to its image_type - structure. Value is null if SYMBOL is not a known image type. */ - -static INLINE struct image_type * -lookup_image_type (symbol) - Lisp_Object symbol; -{ - struct image_type *type; - - for (type = image_types; type; type = type->next) - if (EQ (symbol, *type->type)) - break; - - return type; -} - - -/* Value is non-zero if OBJECT is a valid Lisp image specification. A - valid image specification is a list whose car is the symbol - `image', and whose rest is a property list. The property list must - contain a value for key `:type'. That value must be the name of a - supported image type. The rest of the property list depends on the - image type. */ - -int -valid_image_p (object) - Lisp_Object object; -{ - int valid_p = 0; - - if (CONSP (object) && EQ (XCAR (object), Qimage)) - { - 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; -} - - -/* Log error message with format string FORMAT and argument ARG. - Signaling an error, e.g. when an image cannot be loaded, is not a - good idea because this would interrupt redisplay, and the error - message display would lead to another redisplay. This function - therefore simply displays a message. */ - -static void -image_error (format, arg1, arg2) - char *format; - Lisp_Object arg1, arg2; -{ - add_to_log (format, arg1, arg2); -} - - - -/*********************************************************************** - Image specifications - ***********************************************************************/ - -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, - IMAGE_FUNCTION_VALUE, - IMAGE_NUMBER_VALUE, - IMAGE_BOOL_VALUE -}; - -/* Structure used when parsing image specifications. */ - -struct image_keyword -{ - /* Name of keyword. */ - char *name; - - /* The type of value allowed. */ - enum image_value_type type; - - /* Non-zero means key must be present. */ - int mandatory_p; - - /* Used to recognize duplicate keywords in a property list. */ - int count; - - /* The value that was found. */ - Lisp_Object value; -}; - - -static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *, - int, Lisp_Object)); -static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *)); - - -/* Parse image spec SPEC according to KEYWORDS. A valid image spec - has the format (image KEYWORD VALUE ...). One of the keyword/ - value pairs must be `:type TYPE'. KEYWORDS is a vector of - image_keywords structures of size NKEYWORDS describing other - allowed keyword/value pairs. Value is non-zero if SPEC is valid. */ - -static int -parse_image_spec (spec, keywords, nkeywords, type) - Lisp_Object spec; - struct image_keyword *keywords; - int nkeywords; - Lisp_Object type; -{ - int i; - Lisp_Object plist; - - if (!CONSP (spec) || !EQ (XCAR (spec), Qimage)) - return 0; - - plist = XCDR (spec); - while (CONSP (plist)) - { - Lisp_Object key, value; - - /* First element of a pair must be a symbol. */ - key = XCAR (plist); - plist = XCDR (plist); - if (!SYMBOLP (key)) - return 0; - - /* There must follow a value. */ - if (!CONSP (plist)) - return 0; - value = XCAR (plist); - plist = XCDR (plist); - - /* Find key in KEYWORDS. Error if not found. */ - for (i = 0; i < nkeywords; ++i) - if (strcmp (keywords[i].name, SDATA (SYMBOL_NAME (key))) == 0) - break; - - if (i == nkeywords) - continue; - - /* Record that we recognized the keyword. If a keywords - was found more than once, it's an error. */ - keywords[i].value = value; - ++keywords[i].count; - - if (keywords[i].count > 1) - return 0; - - /* Check type of value against allowed type. */ - switch (keywords[i].type) - { - case IMAGE_STRING_VALUE: - if (!STRINGP (value)) - 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; - break; - - case IMAGE_POSITIVE_INTEGER_VALUE: - if (!INTEGERP (value) || XINT (value) <= 0) - 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; - else if (INTEGERP (value) - && XINT (value) >= 0 - && XINT (value) <= 100) - break; - return 0; - - case IMAGE_NON_NEGATIVE_INTEGER_VALUE: - if (!INTEGERP (value) || XINT (value) < 0) - return 0; - break; - - case IMAGE_DONT_CHECK_VALUE_TYPE: - break; - - case IMAGE_FUNCTION_VALUE: - value = indirect_function (value); - if (SUBRP (value) - || COMPILEDP (value) - || (CONSP (value) && EQ (XCAR (value), Qlambda))) - break; - return 0; - - case IMAGE_NUMBER_VALUE: - if (!INTEGERP (value) && !FLOATP (value)) - return 0; - break; - - case IMAGE_INTEGER_VALUE: - if (!INTEGERP (value)) - return 0; - break; - - case IMAGE_BOOL_VALUE: - if (!NILP (value) && !EQ (value, Qt)) - return 0; - break; - - default: - abort (); - break; - } - - if (EQ (key, QCtype) && !EQ (type, value)) - return 0; - } - - /* Check that all mandatory fields are present. */ - for (i = 0; i < nkeywords; ++i) - if (keywords[i].mandatory_p && keywords[i].count == 0) - return 0; - - return NILP (plist); -} - - -/* Return the value of KEY in image specification SPEC. Value is nil - if KEY is not present in SPEC. if FOUND is not null, set *FOUND - to 1 if KEY was found in SPEC, set it to 0 otherwise. */ - -static Lisp_Object -image_spec_value (spec, key, found) - Lisp_Object spec, key; - int *found; -{ - Lisp_Object tail; - - xassert (valid_image_p (spec)); - - for (tail = XCDR (spec); - CONSP (tail) && CONSP (XCDR (tail)); - tail = XCDR (XCDR (tail))) - { - if (EQ (XCAR (tail), key)) - { - if (found) - *found = 1; - return XCAR (XCDR (tail)); - } - } - - if (found) - *found = 0; - return Qnil; -} - - -DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0, - doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT). -PIXELS non-nil means return the size in pixels, otherwise return the -size in canonical character units. -FRAME is the frame on which the image will be displayed. FRAME nil -or omitted means use the selected frame. */) - (spec, pixels, frame) - Lisp_Object spec, pixels, frame; -{ - Lisp_Object size; - - size = Qnil; - if (valid_image_p (spec)) - { - 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->hmargin; - int height = img->height + 2 * img->vmargin; - - if (NILP (pixels)) - size = Fcons (make_float ((double) width / FRAME_COLUMN_WIDTH (f)), - make_float ((double) height / FRAME_LINE_HEIGHT (f))); - else - size = Fcons (make_number (width), make_number (height)); - } - else - error ("Invalid image specification"); - - return size; -} - - -DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0, - doc: /* Return t if image SPEC has a mask bitmap. -FRAME is the frame on which the image will be displayed. FRAME nil -or omitted means use the selected frame. */) - (spec, frame) - Lisp_Object spec, frame; -{ - Lisp_Object mask; - - mask = Qnil; - if (valid_image_p (spec)) - { - struct frame *f = check_x_frame (frame); - int id = lookup_image (f, spec); - struct image *img = IMAGE_FROM_ID (f, id); - if (img->mask) - mask = Qt; - } - else - error ("Invalid image specification"); - - return mask; -} - - - -/*********************************************************************** - Image type independent image structures - ***********************************************************************/ - -static struct image *make_image P_ ((Lisp_Object spec, unsigned hash)); -static void free_image P_ ((struct frame *f, struct image *img)); - - -/* Allocate and return a new image structure for image specification - SPEC. SPEC has a hash value of HASH. */ - -static struct image * -make_image (spec, hash) - Lisp_Object spec; - unsigned hash; -{ - struct image *img = (struct image *) xmalloc (sizeof *img); - - xassert (valid_image_p (spec)); - bzero (img, sizeof *img); - img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL)); - xassert (img->type != NULL); - img->spec = spec; - img->data.lisp_val = Qnil; - img->ascent = DEFAULT_IMAGE_ASCENT; - img->hash = hash; - return img; -} - - -/* Free image IMG which was used on frame F, including its resources. */ - -static void -free_image (f, img) - struct frame *f; - struct image *img; -{ - if (img) - { - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - - /* Remove IMG from the hash table of its cache. */ - if (img->prev) - img->prev->next = img->next; - else - c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next; - - if (img->next) - img->next->prev = img->prev; - - c->images[img->id] = NULL; - - /* Free resources, then free IMG. */ - img->type->free (f, img); - xfree (img); - } -} - - -/* Prepare image IMG for display on frame F. Must be called before - drawing an image. */ - -void -prepare_image_for_display (f, img) - struct frame *f; - struct image *img; -{ - EMACS_TIME t; - - /* We're about to display IMG, so set its timestamp to `now'. */ - EMACS_GET_TIME (t); - img->timestamp = EMACS_SECS (t); - - /* If IMG doesn't have a pixmap yet, load it now, using the image - type dependent loader function. */ - if (img->pixmap == None && !img->load_failed_p) - img->load_failed_p = img->type->load (f, img) == 0; -} - - -/* Value is the number of pixels for the ascent of image IMG when - drawn in face FACE. */ - -int -image_ascent (img, face) - struct image *img; - struct face *face; -{ - int height = img->height + img->vmargin; - int ascent; - - if (img->ascent == CENTERED_IMAGE_ASCENT) - { - if (face->font) - /* This expression is arranged so that if the image can't be - exactly centered, it will be moved slightly up. This is - because a typical font is `top-heavy' (due to the presence - uppercase letters), so the image placement should err towards - being top-heavy too. It also just generally looks better. */ - ascent = (height + face->font->ascent - face->font->descent + 1) / 2; - else - ascent = height / 2; - } - else - ascent = height * img->ascent / 100.0; - - return ascent; -} - - -/* Image background colors. */ - -static unsigned long -four_corners_best (ximg, width, height) - XImage *ximg; - unsigned long width, height; -{ - unsigned long corners[4], best; - int i, best_count; - - /* Get the colors at the corners of ximg. */ - corners[0] = XGetPixel (ximg, 0, 0); - corners[1] = XGetPixel (ximg, width - 1, 0); - corners[2] = XGetPixel (ximg, width - 1, height - 1); - corners[3] = XGetPixel (ximg, 0, height - 1); - - /* Choose the most frequently found color as background. */ - for (i = best_count = 0; i < 4; ++i) - { - int j, n; - - for (j = n = 0; j < 4; ++j) - if (corners[i] == corners[j]) - ++n; - - if (n > best_count) - best = corners[i], best_count = n; - } - - return best; -} - -/* Return the `background' field of IMG. If IMG doesn't have one yet, - it is guessed heuristically. If non-zero, XIMG is an existing XImage - object to use for the heuristic. */ - -unsigned long -image_background (img, f, ximg) - struct image *img; - struct frame *f; - XImage *ximg; -{ - if (! img->background_valid) - /* IMG doesn't have a background yet, try to guess a reasonable value. */ - { - int free_ximg = !ximg; - - if (! ximg) - ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap, - 0, 0, img->width, img->height, ~0, ZPixmap); - - img->background = four_corners_best (ximg, img->width, img->height); - - if (free_ximg) - XDestroyImage (ximg); - - img->background_valid = 1; - } - - return img->background; -} - -/* Return the `background_transparent' field of IMG. If IMG doesn't - have one yet, it is guessed heuristically. If non-zero, MASK is an - existing XImage object to use for the heuristic. */ - -int -image_background_transparent (img, f, mask) - struct image *img; - struct frame *f; - XImage *mask; -{ - if (! img->background_transparent_valid) - /* IMG doesn't have a background yet, try to guess a reasonable value. */ - { - if (img->mask) - { - int free_mask = !mask; - - if (! mask) - mask = XGetImage (FRAME_X_DISPLAY (f), img->mask, - 0, 0, img->width, img->height, ~0, ZPixmap); - - img->background_transparent - = !four_corners_best (mask, img->width, img->height); - - if (free_mask) - XDestroyImage (mask); - } - else - img->background_transparent = 0; - - img->background_transparent_valid = 1; - } - - return img->background_transparent; -} - - -/*********************************************************************** - Helper functions for X image types - ***********************************************************************/ - -static void x_clear_image_1 P_ ((struct frame *, struct image *, int, - int, int)); -static void x_clear_image P_ ((struct frame *f, struct image *img)); -static unsigned long x_alloc_image_color P_ ((struct frame *f, - struct image *img, - Lisp_Object color_name, - unsigned long dflt)); - - -/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means - free the pixmap if any. MASK_P non-zero means clear the mask - pixmap if any. COLORS_P non-zero means free colors allocated for - the image, if any. */ - -static void -x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p) - struct frame *f; - struct image *img; - int pixmap_p, mask_p, colors_p; -{ - if (pixmap_p && img->pixmap) - { - XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap); - img->pixmap = None; - img->background_valid = 0; - } - - if (mask_p && img->mask) - { - XFreePixmap (FRAME_X_DISPLAY (f), img->mask); - img->mask = None; - img->background_transparent_valid = 0; - } - - if (colors_p && img->ncolors) - { - x_free_colors (f, img->colors, img->ncolors); - xfree (img->colors); - img->colors = NULL; - img->ncolors = 0; - } -} - -/* Free X resources of image IMG which is used on frame F. */ - -static void -x_clear_image (f, img) - struct frame *f; - struct image *img; -{ - BLOCK_INPUT; - x_clear_image_1 (f, img, 1, 1, 1); - UNBLOCK_INPUT; -} - - -/* Allocate color COLOR_NAME for image IMG on frame F. If color - cannot be allocated, use DFLT. Add a newly allocated color to - IMG->colors, so that it can be freed again. Value is the pixel - color. */ - -static unsigned long -x_alloc_image_color (f, img, color_name, dflt) - struct frame *f; - struct image *img; - Lisp_Object color_name; - unsigned long dflt; -{ - XColor color; - unsigned long result; - - xassert (STRINGP (color_name)); - - if (x_defined_color (f, SDATA (color_name), &color, 1)) - { - /* This isn't called frequently so we get away with simply - reallocating the color vector to the needed size, here. */ - ++img->ncolors; - img->colors = - (unsigned long *) xrealloc (img->colors, - img->ncolors * sizeof *img->colors); - img->colors[img->ncolors - 1] = color.pixel; - result = color.pixel; - } - else - result = dflt; - - return result; -} - - - -/*********************************************************************** - Image Cache + Window properties ***********************************************************************/ -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 - heap. Call free_image_cache to free an image cache. */ - -struct image_cache * -make_image_cache () -{ - struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c); - int size; - - bzero (c, sizeof *c); - c->size = 50; - c->images = (struct image **) xmalloc (c->size * sizeof *c->images); - size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets; - c->buckets = (struct image **) xmalloc (size); - bzero (c->buckets, size); - return c; -} - - -/* Free image cache of frame F. Be aware that X frames share images - caches. */ - -void -free_image_cache (f) - struct frame *f; -{ - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - if (c) - { - int i; - - /* Cache should not be referenced by any frame when freed. */ - xassert (c->refcount == 0); - - for (i = 0; i < c->used; ++i) - free_image (f, c->images[i]); - xfree (c->images); - xfree (c->buckets); - xfree (c); - FRAME_X_IMAGE_CACHE (f) = NULL; - } -} - - -/* Clear image cache of frame F. FORCE_P non-zero means free all - images. FORCE_P zero means clear only images that haven't been - displayed for some time. Should be called from time to time to - reduce the number of loaded images. If image-eviction-seconds is - non-nil, this frees images in the cache which weren't displayed for - at least that many seconds. */ - -void -clear_image_cache (f, force_p) - struct frame *f; - int force_p; -{ - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - - if (c && INTEGERP (Vimage_cache_eviction_delay)) - { - EMACS_TIME t; - unsigned long old; - int i, nfreed; - - EMACS_GET_TIME (t); - old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay); - - /* Block input so that we won't be interrupted by a SIGIO - while being in an inconsistent state. */ - BLOCK_INPUT; - - for (i = nfreed = 0; i < c->used; ++i) - { - struct image *img = c->images[i]; - if (img != NULL - && (force_p || img->timestamp < old)) - { - free_image (f, img); - ++nfreed; - } - } - - /* We may be clearing the image cache because, for example, - Emacs was iconified for a longer period of time. In that - case, current matrices may still contain references to - images freed above. So, clear these matrices. */ - if (nfreed) - { - Lisp_Object tail, frame; - - FOR_EACH_FRAME (tail, frame) - { - struct frame *f = XFRAME (frame); - if (FRAME_X_P (f) - && FRAME_X_IMAGE_CACHE (f) == c) - clear_current_matrices (f); - } - - ++windows_or_buffers_changed; - } - - UNBLOCK_INPUT; - } -} - - -DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache, - 0, 1, 0, - doc: /* Clear the image cache of FRAME. +DEFUN ("x-change-window-property", Fx_change_window_property, + Sx_change_window_property, 2, 6, 0, + doc: /* Change window property PROP to VALUE on the X window of FRAME. +PROP must be a string. +VALUE may be a string or a list of conses, numbers and/or strings. +If an element in the list is a string, it is converted to +an Atom and the value of the Atom is used. If an element is a cons, +it is converted to a 32 bit number where the car is the 16 top bits and the +cdr is the lower 16 bits. FRAME nil or omitted means use the selected frame. -FRAME t means clear the image caches of all frames. */) - (frame) - Lisp_Object frame; -{ - if (EQ (frame, Qt)) - { - Lisp_Object tail; - - FOR_EACH_FRAME (tail, frame) - if (FRAME_X_P (XFRAME (frame))) - clear_image_cache (XFRAME (frame), 1); - } - else - clear_image_cache (check_x_frame (frame), 1); - - return Qnil; -} - - -/* 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). */ - -int -lookup_image (f, spec) - struct frame *f; - Lisp_Object spec; -{ - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - struct image *img; - int i; - unsigned hash; - struct gcpro gcpro1; - EMACS_TIME now; - - /* F must be a window-system frame, and SPEC must be a valid image - specification. */ - xassert (FRAME_WINDOW_P (f)); - xassert (valid_image_p (spec)); - - GCPRO1 (spec); - - /* Look up SPEC in the hash table of the image cache. */ - hash = sxhash (spec, 0); - i = hash % IMAGE_CACHE_BUCKETS_SIZE; - - for (img = c->buckets[i]; img; img = img->next) - if (img->hash == hash && !NILP (Fequal (img->spec, spec))) - break; - - /* 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); - 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->load_failed_p) - { - Lisp_Object value; - - value = image_spec_value (spec, QCwidth, NULL); - img->width = (INTEGERP (value) - ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH); - value = image_spec_value (spec, QCheight, NULL); - img->height = (INTEGERP (value) - ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT); - } - else - { - /* Handle image type independent image attributes - `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF', - `:background COLOR'. */ - Lisp_Object ascent, margin, relief, bg; - - ascent = image_spec_value (spec, QCascent, NULL); - if (INTEGERP (ascent)) - img->ascent = XFASTINT (ascent); - else if (EQ (ascent, Qcenter)) - img->ascent = CENTERED_IMAGE_ASCENT; - - margin = image_spec_value (spec, QCmargin, NULL); - if (INTEGERP (margin) && XINT (margin) >= 0) - 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->hmargin += abs (img->relief); - img->vmargin += abs (img->relief); - } - - if (! img->background_valid) - { - bg = image_spec_value (img->spec, QCbackground, NULL); - if (!NILP (bg)) - { - img->background - = x_alloc_image_color (f, img, bg, - FRAME_BACKGROUND_PIXEL (f)); - img->background_valid = 1; - } - } - - /* Do image transformations and compute masks, unless we - don't have the image yet. */ - if (!EQ (*img->type->type, Qpostscript)) - postprocess_image (f, img); - } - - UNBLOCK_INPUT; - xassert (!interrupt_input_blocked); - } - - /* We're using IMG, so set its timestamp to `now'. */ - EMACS_GET_TIME (now); - img->timestamp = EMACS_SECS (now); - - UNGCPRO; - - /* Value is the image id. */ - return img->id; -} - - -/* Cache image IMG in the image cache of frame F. */ - -static void -cache_image (f, img) - struct frame *f; - struct image *img; -{ - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - int i; - - /* Find a free slot in c->images. */ - for (i = 0; i < c->used; ++i) - if (c->images[i] == NULL) - break; - - /* If no free slot found, maybe enlarge c->images. */ - if (i == c->used && c->used == c->size) - { - c->size *= 2; - c->images = (struct image **) xrealloc (c->images, - c->size * sizeof *c->images); - } - - /* Add IMG to c->images, and assign IMG an id. */ - c->images[i] = img; - img->id = i; - if (i == c->used) - ++c->used; - - /* Add IMG to the cache's hash table. */ - i = img->hash % IMAGE_CACHE_BUCKETS_SIZE; - img->next = c->buckets[i]; - if (img->next) - img->next->prev = img; - img->prev = NULL; - c->buckets[i] = img; -} - - -/* Call FN on every image in the image cache of frame F. Used to mark - Lisp Objects in the image cache. */ - -void -forall_images_in_image_cache (f, fn) - struct frame *f; - void (*fn) P_ ((struct image *img)); -{ - if (FRAME_LIVE_P (f) && FRAME_X_P (f)) - { - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - if (c) - { - int i; - for (i = 0; i < c->used; ++i) - if (c->images[i]) - fn (c->images[i]); - } - } -} - - - -/*********************************************************************** - X support code - ***********************************************************************/ - -static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int, - XImage **, Pixmap *)); -static void x_destroy_x_image P_ ((XImage *)); -static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int)); - - -/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on - frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created. - Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated - via xmalloc. Print error messages via image_error if an error - occurs. Value is non-zero if successful. */ - -static int -x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap) - struct frame *f; - int width, height, depth; - XImage **ximg; - Pixmap *pixmap; -{ - Display *display = FRAME_X_DISPLAY (f); - Screen *screen = FRAME_X_SCREEN (f); - Window window = FRAME_X_WINDOW (f); - - xassert (interrupt_input_blocked); - - if (depth <= 0) - depth = DefaultDepthOfScreen (screen); - *ximg = XCreateImage (display, DefaultVisualOfScreen (screen), - depth, ZPixmap, 0, NULL, width, height, - depth > 16 ? 32 : depth > 8 ? 16 : 8, 0); - if (*ximg == NULL) - { - image_error ("Unable to allocate X image", Qnil, Qnil); - return 0; - } - - /* Allocate image raster. */ - (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height); - - /* Allocate a pixmap of the same size. */ - *pixmap = XCreatePixmap (display, window, width, height, depth); - if (*pixmap == None) - { - x_destroy_x_image (*ximg); - *ximg = NULL; - image_error ("Unable to create X pixmap", Qnil, Qnil); - return 0; - } - - return 1; -} - - -/* Destroy XImage XIMG. Free XIMG->data. */ - -static void -x_destroy_x_image (ximg) - XImage *ximg; -{ - xassert (interrupt_input_blocked); - if (ximg) - { - xfree (ximg->data); - ximg->data = NULL; - XDestroyImage (ximg); - } -} - - -/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT - are width and height of both the image and pixmap. */ - -static void -x_put_x_image (f, ximg, pixmap, width, height) - struct frame *f; - XImage *ximg; - Pixmap pixmap; - int width, height; -{ - GC gc; - - xassert (interrupt_input_blocked); - gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL); - XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height); - XFreeGC (FRAME_X_DISPLAY (f), gc); -} - - - -/*********************************************************************** - File Handling - ***********************************************************************/ - -static Lisp_Object x_find_image_file P_ ((Lisp_Object)); -static char *slurp_file P_ ((char *, int *)); - - -/* Find image file FILE. Look in data-directory, then - x-bitmap-file-path. Value is the full name of the file found, or - nil if not found. */ - -static Lisp_Object -x_find_image_file (file) - Lisp_Object file; -{ - Lisp_Object file_found, search_path; - struct gcpro gcpro1, gcpro2; - int fd; - - file_found = Qnil; - search_path = Fcons (Vdata_directory, Vx_bitmap_file_path); - GCPRO2 (file_found, search_path); - - /* Try to find FILE in data-directory, then x-bitmap-file-path. */ - fd = openp (search_path, file, Qnil, &file_found, Qnil); - - if (fd == -1) - file_found = Qnil; - else - close (fd); - - UNGCPRO; - return file_found; -} - - -/* Read FILE into memory. Value is a pointer to a buffer allocated - with xmalloc holding FILE's contents. Value is null if an error - occurred. *SIZE is set to the size of the file. */ - -static char * -slurp_file (file, size) - char *file; - int *size; -{ - FILE *fp = NULL; - char *buf = NULL; - struct stat st; - - if (stat (file, &st) == 0 - && (fp = fopen (file, "r")) != NULL - && (buf = (char *) xmalloc (st.st_size), - fread (buf, 1, st.st_size, fp) == st.st_size)) - { - *size = st.st_size; - fclose (fp); - } - else - { - if (fp) - fclose (fp); - if (buf) - { - xfree (buf); - buf = NULL; - } - } - - return buf; -} - - - -/*********************************************************************** - XBM images - ***********************************************************************/ - -static int xbm_scan P_ ((char **, char *, char *, int *)); -static int xbm_load P_ ((struct frame *f, struct image *img)); -static int xbm_load_image P_ ((struct frame *f, struct image *img, - char *, char *)); -static int xbm_image_p P_ ((Lisp_Object object)); -static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *, - unsigned char **)); -static int xbm_file_p P_ ((Lisp_Object)); - - -/* Indices of image specification fields in xbm_format, below. */ - -enum xbm_keyword_index -{ - XBM_TYPE, - XBM_FILE, - XBM_WIDTH, - XBM_HEIGHT, - XBM_DATA, - XBM_FOREGROUND, - XBM_BACKGROUND, - XBM_ASCENT, - XBM_MARGIN, - XBM_RELIEF, - XBM_ALGORITHM, - XBM_HEURISTIC_MASK, - XBM_MASK, - XBM_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid XBM image specifications. */ - -static struct image_keyword xbm_format[XBM_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":file", IMAGE_STRING_VALUE, 0}, - {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0}, - {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0}, - {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 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_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 0}, - {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} -}; - -/* Structure describing the image type XBM. */ - -static struct image_type xbm_type = -{ - &Qxbm, - xbm_image_p, - xbm_load, - x_clear_image, - NULL -}; - -/* Tokens returned from xbm_scan. */ - -enum xbm_token -{ - XBM_TK_IDENT = 256, - XBM_TK_NUMBER -}; - - -/* Return non-zero if OBJECT is a valid XBM-type image specification. - A valid specification is a list starting with the symbol `image' - The rest of the list is a property list which must contain an - entry `:type xbm.. - - If the specification specifies a file to load, it must contain - an entry `:file FILENAME' where FILENAME is a string. - - If the specification is for a bitmap loaded from memory it must - contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where - WIDTH and HEIGHT are integers > 0. DATA may be: - - 1. a string large enough to hold the bitmap data, i.e. it must - have a size >= (WIDTH + 7) / 8 * HEIGHT - - 2. a bool-vector of size >= WIDTH * HEIGHT - - 3. a vector of strings or bool-vectors, one for each line of the - bitmap. - - 4. A string containing an in-memory XBM file. WIDTH and HEIGHT - may not be specified in this case because they are defined in the - XBM file. - - Both the file and data forms may contain the additional entries - `:background COLOR' and `:foreground COLOR'. If not present, - foreground and background of the frame on which the image is - displayed is used. */ - -static int -xbm_image_p (object) - Lisp_Object object; +If TYPE is given and non-nil, it is the name of the type of VALUE. +If TYPE is not given or nil, the type is STRING. +FORMAT gives the size in bits of each element if VALUE is a list. +It must be one of 8, 16 or 32. +If VALUE is a string or FORMAT is nil or not given, FORMAT defaults to 8. +If OUTER_P is non-nil, the property is changed for the outer X window of +FRAME. Default is to change on the edit X window. + +Value is VALUE. */) + (prop, value, frame, type, format, outer_p) + Lisp_Object prop, value, frame, type, format, outer_p; { - struct image_keyword kw[XBM_LAST]; - - bcopy (xbm_format, kw, sizeof kw); - if (!parse_image_spec (object, kw, XBM_LAST, Qxbm)) - return 0; - - xassert (EQ (kw[XBM_TYPE].value, Qxbm)); - - if (kw[XBM_FILE].count) - { - if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count) - return 0; - } - else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value)) - { - /* In-memory XBM file. */ - if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count) - return 0; - } - else - { - Lisp_Object data; - int width, height; - - /* Entries for `:width', `:height' and `:data' must be present. */ - if (!kw[XBM_WIDTH].count - || !kw[XBM_HEIGHT].count - || !kw[XBM_DATA].count) - return 0; - - data = kw[XBM_DATA].value; - width = XFASTINT (kw[XBM_WIDTH].value); - height = XFASTINT (kw[XBM_HEIGHT].value); - - /* Check type of data, and width and height against contents of - data. */ - if (VECTORP (data)) - { - int i; - - /* Number of elements of the vector must be >= height. */ - if (XVECTOR (data)->size < height) - return 0; - - /* Each string or bool-vector in data must be large enough - for one line of the image. */ - for (i = 0; i < height; ++i) - { - Lisp_Object elt = XVECTOR (data)->contents[i]; - - if (STRINGP (elt)) - { - if (SCHARS (elt) - < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR) - return 0; - } - else if (BOOL_VECTOR_P (elt)) - { - if (XBOOL_VECTOR (elt)->size < width) - return 0; - } - else - return 0; - } - } - else if (STRINGP (data)) - { - if (SCHARS (data) - < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height) - return 0; - } - else if (BOOL_VECTOR_P (data)) - { - if (XBOOL_VECTOR (data)->size < width * height) - return 0; - } - else - return 0; - } - - return 1; -} - - -/* Scan a bitmap file. FP is the stream to read from. Value is - either an enumerator from enum xbm_token, or a character for a - single-character token, or 0 at end of file. If scanning an - identifier, store the lexeme of the identifier in SVAL. If - scanning a number, store its value in *IVAL. */ - -static int -xbm_scan (s, end, sval, ival) - char **s, *end; - char *sval; - int *ival; -{ - int c; - - loop: - - /* Skip white space. */ - while (*s < end && (c = *(*s)++, isspace (c))) - ; - - if (*s >= end) - c = 0; - else if (isdigit (c)) - { - int value = 0, digit; - - if (c == '0' && *s < end) - { - c = *(*s)++; - if (c == 'x' || c == 'X') - { - while (*s < end) - { - c = *(*s)++; - if (isdigit (c)) - digit = c - '0'; - else if (c >= 'a' && c <= 'f') - digit = c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - digit = c - 'A' + 10; - else - break; - value = 16 * value + digit; - } - } - else if (isdigit (c)) - { - value = c - '0'; - while (*s < end - && (c = *(*s)++, isdigit (c))) - value = 8 * value + c - '0'; - } - } - else - { - value = c - '0'; - while (*s < end - && (c = *(*s)++, isdigit (c))) - value = 10 * value + c - '0'; - } - - if (*s < end) - *s = *s - 1; - *ival = value; - c = XBM_TK_NUMBER; - } - else if (isalpha (c) || c == '_') - { - *sval++ = c; - while (*s < end - && (c = *(*s)++, (isalnum (c) || c == '_'))) - *sval++ = c; - *sval = 0; - if (*s < end) - *s = *s - 1; - c = XBM_TK_IDENT; - } - else if (c == '/' && **s == '*') - { - /* C-style comment. */ - ++*s; - while (**s && (**s != '*' || *(*s + 1) != '/')) - ++*s; - if (**s) - { - *s += 2; - goto loop; - } - } - - return c; -} - - -/* Replacement for XReadBitmapFileData which isn't available under old - X versions. CONTENTS is a pointer to a buffer to parse; END is the - buffer's end. Set *WIDTH and *HEIGHT to the width and height of - the image. Return in *DATA the bitmap data allocated with xmalloc. - Value is non-zero if successful. DATA null means just test if - CONTENTS looks like an in-memory XBM file. */ - -static int -xbm_read_bitmap_data (contents, end, width, height, data) - char *contents, *end; - int *width, *height; - unsigned char **data; -{ - char *s = contents; - char buffer[BUFSIZ]; - int padding_p = 0; - int v10 = 0; - int bytes_per_line, i, nbytes; - unsigned char *p; - int value; - int LA1; - -#define match() \ - LA1 = xbm_scan (&s, end, buffer, &value) - -#define expect(TOKEN) \ - if (LA1 != (TOKEN)) \ - goto failure; \ - else \ - match () - -#define expect_ident(IDENT) \ - if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \ - match (); \ - else \ - goto failure - - *width = *height = -1; - if (data) - *data = NULL; - LA1 = xbm_scan (&s, end, buffer, &value); - - /* Parse defines for width, height and hot-spots. */ - while (LA1 == '#') - { - match (); - expect_ident ("define"); - expect (XBM_TK_IDENT); - - if (LA1 == XBM_TK_NUMBER); - { - char *p = strrchr (buffer, '_'); - p = p ? p + 1 : buffer; - if (strcmp (p, "width") == 0) - *width = value; - else if (strcmp (p, "height") == 0) - *height = value; - } - expect (XBM_TK_NUMBER); - } - - if (*width < 0 || *height < 0) - goto failure; - else if (data == NULL) - goto success; - - /* Parse bits. Must start with `static'. */ - expect_ident ("static"); - if (LA1 == XBM_TK_IDENT) - { - if (strcmp (buffer, "unsigned") == 0) - { - match (); - expect_ident ("char"); - } - else if (strcmp (buffer, "short") == 0) - { - match (); - v10 = 1; - if (*width % 16 && *width % 16 < 9) - padding_p = 1; - } - else if (strcmp (buffer, "char") == 0) - match (); - else - goto failure; - } - else - goto failure; - - expect (XBM_TK_IDENT); - expect ('['); - expect (']'); - expect ('='); - expect ('{'); - - bytes_per_line = (*width + 7) / 8 + padding_p; - nbytes = bytes_per_line * *height; - p = *data = (char *) xmalloc (nbytes); - - if (v10) - { - for (i = 0; i < nbytes; i += 2) - { - int val = value; - expect (XBM_TK_NUMBER); - - *p++ = val; - if (!padding_p || ((i + 2) % bytes_per_line)) - *p++ = value >> 8; - - if (LA1 == ',' || LA1 == '}') - match (); - else - goto failure; - } - } - else - { - for (i = 0; i < nbytes; ++i) - { - int val = value; - expect (XBM_TK_NUMBER); - - *p++ = val; - - if (LA1 == ',' || LA1 == '}') - match (); - else - goto failure; - } - } - - success: - return 1; - - failure: - - if (data && *data) - { - xfree (*data); - *data = NULL; - } - return 0; - -#undef match -#undef expect -#undef expect_ident -} - - -/* Load XBM image IMG which will be displayed on frame F from buffer - CONTENTS. END is the end of the buffer. Value is non-zero if - successful. */ - -static int -xbm_load_image (f, img, contents, end) - struct frame *f; - struct image *img; - char *contents, *end; -{ - int rc; + struct frame *f = check_x_frame (frame); + Atom prop_atom; + Atom target_type = XA_STRING; + int element_format = 8; unsigned char *data; - int success_p = 0; - - rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data); - if (rc) - { - int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f)); - unsigned long foreground = FRAME_FOREGROUND_PIXEL (f); - unsigned long background = FRAME_BACKGROUND_PIXEL (f); - Lisp_Object value; - - xassert (img->width > 0 && img->height > 0); - - /* Get foreground and background colors, maybe allocate colors. */ - value = image_spec_value (img->spec, QCforeground, NULL); - if (!NILP (value)) - foreground = x_alloc_image_color (f, img, value, foreground); - value = image_spec_value (img->spec, QCbackground, NULL); - if (!NILP (value)) - { - background = x_alloc_image_color (f, img, value, background); - img->background = background; - img->background_valid = 1; - } - - img->pixmap - = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f), - FRAME_X_WINDOW (f), - data, - img->width, img->height, - foreground, background, - depth); - xfree (data); - - if (img->pixmap == None) - { - x_clear_image (f, img); - image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil); - } - else - success_p = 1; - } - else - image_error ("Error loading XBM image `%s'", img->spec, Qnil); - - return success_p; -} - - -/* Value is non-zero if DATA looks like an in-memory XBM file. */ - -static int -xbm_file_p (data) - Lisp_Object data; -{ - int w, h; - return (STRINGP (data) - && xbm_read_bitmap_data (SDATA (data), - (SDATA (data) - + SBYTES (data)), - &w, &h, NULL)); -} - - -/* Fill image IMG which is used on frame F with pixmap data. Value is - non-zero if successful. */ - -static int -xbm_load (f, img) - struct frame *f; - struct image *img; -{ - int success_p = 0; - Lisp_Object file_name; - - xassert (xbm_image_p (img->spec)); - - /* If IMG->spec specifies a file name, create a non-file spec from it. */ - file_name = image_spec_value (img->spec, QCfile, NULL); - if (STRINGP (file_name)) - { - Lisp_Object file; - char *contents; - int size; - struct gcpro gcpro1; - - file = x_find_image_file (file_name); - GCPRO1 (file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", file_name, Qnil); - UNGCPRO; - return 0; - } - - contents = slurp_file (SDATA (file), &size); - if (contents == NULL) - { - image_error ("Error loading XBM image `%s'", img->spec, Qnil); - UNGCPRO; - return 0; - } - - success_p = xbm_load_image (f, img, contents, contents + size); - UNGCPRO; - } - else - { - struct image_keyword fmt[XBM_LAST]; - Lisp_Object data; - int depth; - unsigned long foreground = FRAME_FOREGROUND_PIXEL (f); - unsigned long background = FRAME_BACKGROUND_PIXEL (f); - char *bits; - int parsed_p; - int in_memory_file_p = 0; - - /* See if data looks like an in-memory XBM file. */ - data = image_spec_value (img->spec, QCdata, NULL); - in_memory_file_p = xbm_file_p (data); - - /* Parse the image specification. */ - bcopy (xbm_format, fmt, sizeof fmt); - parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm); - xassert (parsed_p); - - /* Get specified width, and height. */ - if (!in_memory_file_p) - { - img->width = XFASTINT (fmt[XBM_WIDTH].value); - img->height = XFASTINT (fmt[XBM_HEIGHT].value); - xassert (img->width > 0 && img->height > 0); - } - - /* Get foreground and background colors, maybe allocate colors. */ - 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 - && STRINGP (fmt[XBM_BACKGROUND].value)) - background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value, - background); - - if (in_memory_file_p) - success_p = xbm_load_image (f, img, SDATA (data), - (SDATA (data) - + SBYTES (data))); - else - { - if (VECTORP (data)) - { - int i; - char *p; - int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR; - - p = bits = (char *) alloca (nbytes * img->height); - for (i = 0; i < img->height; ++i, p += nbytes) - { - Lisp_Object line = XVECTOR (data)->contents[i]; - if (STRINGP (line)) - bcopy (SDATA (line), p, nbytes); - else - bcopy (XBOOL_VECTOR (line)->data, p, nbytes); - } - } - else if (STRINGP (data)) - bits = SDATA (data); - else - bits = XBOOL_VECTOR (data)->data; - - /* Create the pixmap. */ - depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f)); - img->pixmap - = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f), - FRAME_X_WINDOW (f), - bits, - img->width, img->height, - foreground, background, - depth); - if (img->pixmap) - success_p = 1; - else - { - image_error ("Unable to create pixmap for XBM image `%s'", - img->spec, Qnil); - x_clear_image (f, img); - } - } - } - - return success_p; -} - - - -/*********************************************************************** - XPM images - ***********************************************************************/ - -#if HAVE_XPM - -static int xpm_image_p P_ ((Lisp_Object object)); -static int xpm_load P_ ((struct frame *f, struct image *img)); -static int xpm_valid_color_symbols_p P_ ((Lisp_Object)); - -#include "X11/xpm.h" - -/* The symbol `xpm' identifying XPM-format images. */ - -Lisp_Object Qxpm; - -/* Indices of image specification fields in xpm_format, below. */ - -enum xpm_keyword_index -{ - XPM_TYPE, - XPM_FILE, - XPM_DATA, - XPM_ASCENT, - XPM_MARGIN, - XPM_RELIEF, - XPM_ALGORITHM, - XPM_HEURISTIC_MASK, - XPM_MASK, - XPM_COLOR_SYMBOLS, - XPM_BACKGROUND, - XPM_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid XPM image specifications. */ - -static struct image_keyword xpm_format[XPM_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":file", IMAGE_STRING_VALUE, 0}, - {":data", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 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}, - {":background", IMAGE_STRING_OR_NIL_VALUE, 0} -}; - -/* Structure describing the image type XBM. */ - -static struct image_type xpm_type = -{ - &Qxpm, - xpm_image_p, - xpm_load, - x_clear_image, - NULL -}; - - -/* Define ALLOC_XPM_COLORS if we can use Emacs' own color allocation - functions for allocating image colors. Our own functions handle - color allocation failures more gracefully than the ones on the XPM - lib. */ - -#if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure -#define ALLOC_XPM_COLORS -#endif - -#ifdef ALLOC_XPM_COLORS - -static void xpm_init_color_cache P_ ((struct frame *, XpmAttributes *)); -static void xpm_free_color_cache P_ ((void)); -static int xpm_lookup_color P_ ((struct frame *, char *, XColor *)); -static int xpm_color_bucket P_ ((char *)); -static struct xpm_cached_color *xpm_cache_color P_ ((struct frame *, char *, - XColor *, int)); - -/* An entry in a hash table used to cache color definitions of named - colors. This cache is necessary to speed up XPM image loading in - case we do color allocations ourselves. Without it, we would need - a call to XParseColor per pixel in the image. */ - -struct xpm_cached_color -{ - /* Next in collision chain. */ - struct xpm_cached_color *next; - - /* Color definition (RGB and pixel color). */ - XColor color; - - /* Color name. */ - char name[1]; -}; - -/* The hash table used for the color cache, and its bucket vector - size. */ - -#define XPM_COLOR_CACHE_BUCKETS 1001 -struct xpm_cached_color **xpm_color_cache; - -/* Initialize the color cache. */ - -static void -xpm_init_color_cache (f, attrs) - struct frame *f; - XpmAttributes *attrs; -{ - size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache; - xpm_color_cache = (struct xpm_cached_color **) xmalloc (nbytes); - memset (xpm_color_cache, 0, nbytes); - init_color_table (); - - if (attrs->valuemask & XpmColorSymbols) - { - int i; - XColor color; - - for (i = 0; i < attrs->numsymbols; ++i) - if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), - attrs->colorsymbols[i].value, &color)) - { - color.pixel = lookup_rgb_color (f, color.red, color.green, - color.blue); - xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1); - } - } -} - - -/* Free the color cache. */ - -static void -xpm_free_color_cache () -{ - struct xpm_cached_color *p, *next; - int i; - - for (i = 0; i < XPM_COLOR_CACHE_BUCKETS; ++i) - for (p = xpm_color_cache[i]; p; p = next) - { - next = p->next; - xfree (p); - } - - xfree (xpm_color_cache); - xpm_color_cache = NULL; - free_color_table (); -} - - -/* Return the bucket index for color named COLOR_NAME in the color - cache. */ - -static int -xpm_color_bucket (color_name) - char *color_name; -{ - unsigned h = 0; - char *s; - - for (s = color_name; *s; ++s) - h = (h << 2) ^ *s; - return h %= XPM_COLOR_CACHE_BUCKETS; -} - - -/* On frame F, cache values COLOR for color with name COLOR_NAME. - BUCKET, if >= 0, is a precomputed bucket index. Value is the cache - entry added. */ - -static struct xpm_cached_color * -xpm_cache_color (f, color_name, color, bucket) - struct frame *f; - char *color_name; - XColor *color; - int bucket; -{ - size_t nbytes; - struct xpm_cached_color *p; - - if (bucket < 0) - bucket = xpm_color_bucket (color_name); - - nbytes = sizeof *p + strlen (color_name); - p = (struct xpm_cached_color *) xmalloc (nbytes); - strcpy (p->name, color_name); - p->color = *color; - p->next = xpm_color_cache[bucket]; - xpm_color_cache[bucket] = p; - return p; -} - - -/* Look up color COLOR_NAME for frame F in the color cache. If found, - return the cached definition in *COLOR. Otherwise, make a new - entry in the cache and allocate the color. Value is zero if color - allocation failed. */ - -static int -xpm_lookup_color (f, color_name, color) - struct frame *f; - char *color_name; - XColor *color; -{ - struct xpm_cached_color *p; - int h = xpm_color_bucket (color_name); - - for (p = xpm_color_cache[h]; p; p = p->next) - if (strcmp (p->name, color_name) == 0) - break; - - if (p != NULL) - *color = p->color; - else if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), - color_name, color)) - { - color->pixel = lookup_rgb_color (f, color->red, color->green, - color->blue); - p = xpm_cache_color (f, color_name, color, h); - } - /* You get `opaque' at least from ImageMagick converting pbm to xpm - with transparency, and it's useful. */ - else if (strcmp ("opaque", color_name) == 0) - { - bzero (color, sizeof (XColor)); /* Is this necessary/correct? */ - color->pixel = FRAME_FOREGROUND_PIXEL (f); - p = xpm_cache_color (f, color_name, color, h); - } - - return p != NULL; -} - - -/* Callback for allocating color COLOR_NAME. Called from the XPM lib. - CLOSURE is a pointer to the frame on which we allocate the - color. Return in *COLOR the allocated color. Value is non-zero - if successful. */ - -static int -xpm_alloc_color (dpy, cmap, color_name, color, closure) - Display *dpy; - Colormap cmap; - char *color_name; - XColor *color; - void *closure; -{ - return xpm_lookup_color ((struct frame *) closure, color_name, color); -} - - -/* Callback for freeing NPIXELS colors contained in PIXELS. CLOSURE - is a pointer to the frame on which we allocate the color. Value is - non-zero if successful. */ - -static int -xpm_free_colors (dpy, cmap, pixels, npixels, closure) - Display *dpy; - Colormap cmap; - Pixel *pixels; - int npixels; - void *closure; -{ - return 1; -} - -#endif /* ALLOC_XPM_COLORS */ - - -/* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list - for XPM images. Such a list must consist of conses whose car and - cdr are strings. */ - -static int -xpm_valid_color_symbols_p (color_symbols) - Lisp_Object color_symbols; -{ - while (CONSP (color_symbols)) - { - Lisp_Object sym = XCAR (color_symbols); - if (!CONSP (sym) - || !STRINGP (XCAR (sym)) - || !STRINGP (XCDR (sym))) - break; - color_symbols = XCDR (color_symbols); - } - - return NILP (color_symbols); -} - - -/* Value is non-zero if OBJECT is a valid XPM image specification. */ - -static int -xpm_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[XPM_LAST]; - bcopy (xpm_format, fmt, sizeof fmt); - return (parse_image_spec (object, fmt, XPM_LAST, Qxpm) - /* Either `:file' or `:data' must be present. */ - && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1 - /* Either no `:color-symbols' or it's a list of conses - whose car and cdr are strings. */ - && (fmt[XPM_COLOR_SYMBOLS].count == 0 - || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))); -} - - -/* Load image IMG which will be displayed on frame F. Value is - non-zero if successful. */ - -static int -xpm_load (f, img) - struct frame *f; - struct image *img; -{ - int rc; - XpmAttributes attrs; - Lisp_Object specified_file, color_symbols; - - /* Configure the XPM lib. Use the visual of frame F. Allocate - close colors. Return colors allocated. */ - bzero (&attrs, sizeof attrs); - attrs.visual = FRAME_X_VISUAL (f); - attrs.colormap = FRAME_X_COLORMAP (f); - attrs.valuemask |= XpmVisual; - attrs.valuemask |= XpmColormap; - -#ifdef ALLOC_XPM_COLORS - /* Allocate colors with our own functions which handle - failing color allocation more gracefully. */ - attrs.color_closure = f; - attrs.alloc_color = xpm_alloc_color; - attrs.free_colors = xpm_free_colors; - attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure; -#else /* not ALLOC_XPM_COLORS */ - /* Let the XPM lib allocate colors. */ - attrs.valuemask |= XpmReturnAllocPixels; -#ifdef XpmAllocCloseColors - attrs.alloc_close_colors = 1; - attrs.valuemask |= XpmAllocCloseColors; -#else /* not XpmAllocCloseColors */ - attrs.closeness = 600; - attrs.valuemask |= XpmCloseness; -#endif /* not XpmAllocCloseColors */ -#endif /* ALLOC_XPM_COLORS */ - - /* If image specification contains symbolic color definitions, add - these to `attrs'. */ - color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL); - if (CONSP (color_symbols)) - { - Lisp_Object tail; - XpmColorSymbol *xpm_syms; - int i, size; - - attrs.valuemask |= XpmColorSymbols; - - /* Count number of symbols. */ - attrs.numsymbols = 0; - for (tail = color_symbols; CONSP (tail); tail = XCDR (tail)) - ++attrs.numsymbols; - - /* Allocate an XpmColorSymbol array. */ - size = attrs.numsymbols * sizeof *xpm_syms; - xpm_syms = (XpmColorSymbol *) alloca (size); - bzero (xpm_syms, size); - attrs.colorsymbols = xpm_syms; - - /* Fill the color symbol array. */ - for (tail = color_symbols, i = 0; - CONSP (tail); - ++i, tail = XCDR (tail)) - { - Lisp_Object name = XCAR (XCAR (tail)); - Lisp_Object color = XCDR (XCAR (tail)); - xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1); - strcpy (xpm_syms[i].name, SDATA (name)); - xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1); - strcpy (xpm_syms[i].value, SDATA (color)); - } - } - - /* Create a pixmap for the image, either from a file, or from a - string buffer containing data in the same format as an XPM file. */ -#ifdef ALLOC_XPM_COLORS - xpm_init_color_cache (f, &attrs); -#endif - - specified_file = image_spec_value (img->spec, QCfile, NULL); - if (STRINGP (specified_file)) - { - Lisp_Object file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - return 0; - } - - rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - SDATA (file), &img->pixmap, &img->mask, - &attrs); - } - else - { - Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL); - rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - SDATA (buffer), - &img->pixmap, &img->mask, - &attrs); - } - - if (rc == XpmSuccess) - { -#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); - for (i = 0; i < attrs.nalloc_pixels; ++i) - { - img->colors[i] = attrs.alloc_pixels[i]; -#ifdef DEBUG_X_COLORS - register_color (img->colors[i]); -#endif - } -#endif /* not ALLOC_XPM_COLORS */ - - img->width = attrs.width; - img->height = attrs.height; - xassert (img->width > 0 && img->height > 0); - - /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */ - XpmFreeAttributes (&attrs); - } - else - { - switch (rc) - { - case XpmOpenFailed: - image_error ("Error opening XPM file (%s)", img->spec, Qnil); - break; - - case XpmFileInvalid: - image_error ("Invalid XPM file (%s)", img->spec, Qnil); - break; - - case XpmNoMemory: - image_error ("Out of memory (%s)", img->spec, Qnil); - break; - - case XpmColorFailed: - image_error ("Color allocation error (%s)", img->spec, Qnil); - break; - - default: - image_error ("Unknown error (%s)", img->spec, Qnil); - break; - } - } - -#ifdef ALLOC_XPM_COLORS - xpm_free_color_cache (); -#endif - return rc == XpmSuccess; -} + int nelements; + Window w; -#endif /* HAVE_XPM != 0 */ - - -/*********************************************************************** - Color table - ***********************************************************************/ - -/* An entry in the color table mapping an RGB color to a pixel color. */ - -struct ct_color -{ - int r, g, b; - unsigned long pixel; - - /* Next in color table collision list. */ - struct ct_color *next; -}; - -/* The bucket vector size to use. Must be prime. */ - -#define CT_SIZE 101 - -/* Value is a hash of the RGB color given by R, G, and B. */ - -#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B)) - -/* The color hash table. */ - -struct ct_color **ct_table; - -/* Number of entries in the color table. */ - -int ct_colors_allocated; - -/* Initialize the color table. */ - -static void -init_color_table () -{ - int size = CT_SIZE * sizeof (*ct_table); - ct_table = (struct ct_color **) xmalloc (size); - bzero (ct_table, size); - ct_colors_allocated = 0; -} - - -/* Free memory associated with the color table. */ - -static void -free_color_table () -{ - int i; - struct ct_color *p, *next; - - for (i = 0; i < CT_SIZE; ++i) - for (p = ct_table[i]; p; p = next) - { - next = p->next; - xfree (p); - } - - xfree (ct_table); - ct_table = NULL; -} - - -/* Value is a pixel color for RGB color R, G, B on frame F. If an - entry for that color already is in the color table, return the - pixel color of that entry. Otherwise, allocate a new color for R, - G, B, and make an entry in the color table. */ - -static unsigned long -lookup_rgb_color (f, r, g, b) - struct frame *f; - int r, g, b; -{ - unsigned hash = CT_HASH_RGB (r, g, b); - int i = hash % CT_SIZE; - struct ct_color *p; - - for (p = ct_table[i]; p; p = p->next) - if (p->r == r && p->g == g && p->b == b) - break; + CHECK_STRING (prop); - if (p == NULL) + if (! NILP (format)) { - XColor color; - Colormap cmap; - int rc; - - color.red = r; - color.green = g; - color.blue = b; - - cmap = FRAME_X_COLORMAP (f); - rc = x_alloc_nearest_color (f, cmap, &color); + CHECK_NUMBER (format); + element_format = XFASTINT (format); - if (rc) - { - ++ct_colors_allocated; - - p = (struct ct_color *) xmalloc (sizeof *p); - p->r = r; - p->g = g; - p->b = b; - p->pixel = color.pixel; - p->next = ct_table[i]; - ct_table[i] = p; - } - else - return FRAME_FOREGROUND_PIXEL (f); + if (element_format != 8 && element_format != 16 + && element_format != 32) + error ("FORMAT must be one of 8, 16 or 32"); } - return p->pixel; -} - - -/* Look up pixel color PIXEL which is used on frame F in the color - table. If not already present, allocate it. Value is PIXEL. */ - -static unsigned long -lookup_pixel_color (f, pixel) - struct frame *f; - unsigned long pixel; -{ - int i = pixel % CT_SIZE; - struct ct_color *p; - - for (p = ct_table[i]; p; p = p->next) - if (p->pixel == pixel) - break; - - if (p == NULL) + if (CONSP (value)) { - XColor color; - Colormap cmap; - int rc; + nelements = x_check_property_data (value); + if (nelements == -1) + error ("Bad data in VALUE, must be number, string or cons"); - cmap = FRAME_X_COLORMAP (f); - color.pixel = pixel; - x_query_color (f, &color); - rc = x_alloc_nearest_color (f, cmap, &color); - - if (rc) - { - ++ct_colors_allocated; - - p = (struct ct_color *) xmalloc (sizeof *p); - p->r = color.red; - p->g = color.green; - p->b = color.blue; - p->pixel = pixel; - p->next = ct_table[i]; - ct_table[i] = p; - } + if (element_format == 8) + data = (unsigned char *) xmalloc (nelements); + else if (element_format == 16) + data = (unsigned char *) xmalloc (nelements*2); else - return FRAME_FOREGROUND_PIXEL (f); - } - - return p->pixel; -} - - -/* Value is a vector of all pixel colors contained in the color table, - allocated via xmalloc. Set *N to the number of colors. */ + data = (unsigned char *) xmalloc (nelements*4); -static unsigned long * -colors_in_color_table (n) - int *n; -{ - int i, j; - struct ct_color *p; - unsigned long *colors; - - if (ct_colors_allocated == 0) - { - *n = 0; - colors = NULL; + x_fill_property_data (FRAME_X_DISPLAY (f), value, data, element_format); } else { - colors = (unsigned long *) xmalloc (ct_colors_allocated - * sizeof *colors); - *n = ct_colors_allocated; - - for (i = j = 0; i < CT_SIZE; ++i) - for (p = ct_table[i]; p; p = p->next) - colors[j++] = p->pixel; - } - - return colors; -} - - - -/*********************************************************************** - Algorithms - ***********************************************************************/ - -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 `:conversion - disabled'. */ - -int cross_disabled_images; - -/* Edge detection matrices for different edge-detection - strategies. */ - -static int emboss_matrix[9] = { - /* x - 1 x x + 1 */ - 2, -1, 0, /* y - 1 */ - -1, 0, 1, /* y */ - 0, 1, -2 /* y + 1 */ -}; - -static int laplace_matrix[9] = { - /* x - 1 x x + 1 */ - 1, 0, 0, /* y - 1 */ - 0, 0, 0, /* y */ - 0, 0, -1 /* y + 1 */ -}; - -/* Value is the intensity of the color whose red/green/blue values - are R, G, and B. */ - -#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6) - - -/* On frame F, return an array of XColor structures describing image - IMG->pixmap. Each XColor structure has its pixel color set. RGB_P - non-zero means also fill the red/green/blue members of the XColor - structures. Value is a pointer to the array of XColors structures, - allocated with xmalloc; it must be freed by the caller. */ - -static XColor * -x_to_xcolors (f, img, rgb_p) - struct frame *f; - struct image *img; - int rgb_p; -{ - int x, y; - XColor *colors, *p; - XImage *ximg; - - colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors); - - /* Get the X image IMG->pixmap. */ - ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap, - 0, 0, img->width, img->height, ~0, ZPixmap); - - /* Fill the `pixel' members of the XColor array. I wished there - were an easy and portable way to circumvent XGetPixel. */ - p = colors; - for (y = 0; y < img->height; ++y) - { - XColor *row = p; - - for (x = 0; x < img->width; ++x, ++p) - p->pixel = XGetPixel (ximg, x, y); - - if (rgb_p) - x_query_colors (f, row, img->width); - } - - XDestroyImage (ximg); - return colors; -} - - -/* Create IMG->pixmap from an array COLORS of XColor structures, whose - RGB members are set. F is the frame on which this all happens. - COLORS will be freed; an existing IMG->pixmap will be freed, too. */ - -static void -x_from_xcolors (f, img, colors) - struct frame *f; - struct image *img; - XColor *colors; -{ - int x, y; - XImage *oimg; - Pixmap pixmap; - XColor *p; - - init_color_table (); - - x_create_x_image_and_pixmap (f, img->width, img->height, 0, - &oimg, &pixmap); - p = colors; - for (y = 0; y < img->height; ++y) - for (x = 0; x < img->width; ++x, ++p) - { - unsigned long pixel; - pixel = lookup_rgb_color (f, p->red, p->green, p->blue); - XPutPixel (oimg, x, y, pixel); - } - - xfree (colors); - x_clear_image_1 (f, img, 1, 0, 1); - - x_put_x_image (f, oimg, pixmap, img->width, img->height); - x_destroy_x_image (oimg); - img->pixmap = pixmap; - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); -} - - -/* On frame F, perform edge-detection on image IMG. - - MATRIX is a nine-element array specifying the transformation - matrix. See emboss_matrix for an example. - - COLOR_ADJUST is a color adjustment added to each pixel of the - outgoing image. */ - -static void -x_detect_edges (f, img, matrix, color_adjust) - struct frame *f; - struct image *img; - int matrix[9], color_adjust; -{ - XColor *colors = x_to_xcolors (f, img, 1); - XColor *new, *p; - int x, y, i, sum; - - for (i = sum = 0; i < 9; ++i) - sum += abs (matrix[i]); - -#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X)) - - new = (XColor *) xmalloc (img->width * img->height * sizeof *new); - - for (y = 0; y < img->height; ++y) - { - p = COLOR (new, 0, y); - p->red = p->green = p->blue = 0xffff/2; - p = COLOR (new, img->width - 1, y); - p->red = p->green = p->blue = 0xffff/2; - } - - for (x = 1; x < img->width - 1; ++x) - { - p = COLOR (new, x, 0); - p->red = p->green = p->blue = 0xffff/2; - p = COLOR (new, x, img->height - 1); - p->red = p->green = p->blue = 0xffff/2; - } - - for (y = 1; y < img->height - 1; ++y) - { - p = COLOR (new, 1, y); - - for (x = 1; x < img->width - 1; ++x, ++p) - { - int r, g, b, y1, x1; - - r = g = b = i = 0; - for (y1 = y - 1; y1 < y + 2; ++y1) - for (x1 = x - 1; x1 < x + 2; ++x1, ++i) - if (matrix[i]) - { - XColor *t = COLOR (colors, x1, y1); - r += matrix[i] * t->red; - g += matrix[i] * t->green; - b += matrix[i] * t->blue; - } - - r = (r / sum + color_adjust) & 0xffff; - g = (g / sum + color_adjust) & 0xffff; - b = (b / sum + color_adjust) & 0xffff; - p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b); - } - } - - xfree (colors); - x_from_xcolors (f, img, new); - -#undef COLOR -} - - -/* Perform the pre-defined `emboss' edge-detection on image IMG - on frame F. */ - -static void -x_emboss (f, img) - struct frame *f; - struct image *img; -{ - x_detect_edges (f, img, emboss_matrix, 0xffff / 2); -} - - -/* Perform the pre-defined `laplace' edge-detection on image IMG - on frame F. */ - -static void -x_laplace (f, img) - struct frame *f; - struct image *img; -{ - x_detect_edges (f, img, laplace_matrix, 45000); -} - - -/* Perform edge-detection on image IMG on frame F, with specified - transformation matrix MATRIX and color-adjustment COLOR_ADJUST. - - MATRIX must be either - - - a list of at least 9 numbers in row-major form - - a vector of at least 9 numbers - - COLOR_ADJUST nil means use a default; otherwise it must be a - number. */ - -static void -x_edge_detection (f, img, matrix, color_adjust) - struct frame *f; - struct image *img; - Lisp_Object matrix, color_adjust; -{ - int i = 0; - int trans[9]; - - if (CONSP (matrix)) - { - for (i = 0; - i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix)); - ++i, matrix = XCDR (matrix)) - trans[i] = XFLOATINT (XCAR (matrix)); - } - else if (VECTORP (matrix) && ASIZE (matrix) >= 9) - { - for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i) - trans[i] = XFLOATINT (AREF (matrix, i)); - } - - if (NILP (color_adjust)) - color_adjust = make_number (0xffff / 2); - - if (i == 9 && NUMBERP (color_adjust)) - x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust)); -} - - -/* Transform image IMG on frame F so that it looks disabled. */ - -static void -x_disable_image (f, img) - struct frame *f; - struct image *img; -{ - struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); - - if (dpyinfo->n_planes >= 2) - { - /* Color (or grayscale). Convert to gray, and equalize. Just - drawing such images with a stipple can look very odd, so - we're using this method instead. */ - XColor *colors = x_to_xcolors (f, img, 1); - XColor *p, *end; - const int h = 15000; - const int l = 30000; - - for (p = colors, end = colors + img->width * img->height; - p < end; - ++p) - { - int i = COLOR_INTENSITY (p->red, p->green, p->blue); - int i2 = (0xffff - h - l) * i / 0xffff + l; - p->red = p->green = p->blue = i2; - } - - x_from_xcolors (f, img, colors); - } - - /* Draw a cross over the disabled image, if we must or if we - should. */ - if (dpyinfo->n_planes < 2 || cross_disabled_images) - { - Display *dpy = FRAME_X_DISPLAY (f); - GC gc; - - gc = XCreateGC (dpy, img->pixmap, 0, NULL); - XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f)); - XDrawLine (dpy, img->pixmap, gc, 0, 0, - img->width - 1, img->height - 1); - XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1, - img->width - 1, 0); - XFreeGC (dpy, gc); - - if (img->mask) - { - gc = XCreateGC (dpy, img->mask, 0, NULL); - XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f)); - XDrawLine (dpy, img->mask, gc, 0, 0, - img->width - 1, img->height - 1); - XDrawLine (dpy, img->mask, gc, 0, img->height - 1, - img->width - 1, 0); - XFreeGC (dpy, gc); - } + CHECK_STRING (value); + data = SDATA (value); + nelements = SCHARS (value); } -} - - -/* Build a mask for image IMG which is used on frame F. FILE is the - name of an image file, for error messages. HOW determines how to - determine the background color of IMG. If it is a list '(R G B)', - with R, G, and B being integers >= 0, take that as the color of the - background. Otherwise, determine the background color of IMG - heuristically. Value is non-zero if successful. */ - -static int -x_build_heuristic_mask (f, img, how) - struct frame *f; - struct image *img; - Lisp_Object how; -{ - Display *dpy = FRAME_X_DISPLAY (f); - XImage *ximg, *mask_img; - int x, y, rc, use_img_background; - unsigned long bg = 0; - - if (img->mask) - { - XFreePixmap (FRAME_X_DISPLAY (f), img->mask); - img->mask = None; - img->background_transparent_valid = 0; - } - - /* Create an image and pixmap serving as mask. */ - rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1, - &mask_img, &img->mask); - if (!rc) - return 0; - - /* Get the X image of IMG->pixmap. */ - ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height, - ~0, ZPixmap); - - /* Determine the background color of ximg. If HOW is `(R G B)' - take that as color. Otherwise, use the image's background color. */ - use_img_background = 1; - - if (CONSP (how)) - { - int rgb[3], i; - - for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i) - { - rgb[i] = XFASTINT (XCAR (how)) & 0xffff; - how = XCDR (how); - } - - if (i == 3 && NILP (how)) - { - char color_name[30]; - sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]); - bg = x_alloc_image_color (f, img, build_string (color_name), 0); - use_img_background = 0; - } - } - - if (use_img_background) - bg = four_corners_best (ximg, img->width, img->height); - - /* Set all bits in mask_img to 1 whose color in ximg is different - from the background color bg. */ - for (y = 0; y < img->height; ++y) - for (x = 0; x < img->width; ++x) - XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg); - - /* Fill in the background_transparent field while we have the mask handy. */ - image_background_transparent (img, f, mask_img); - - /* Put mask_img into img->mask. */ - x_put_x_image (f, mask_img, img->mask, img->width, img->height); - x_destroy_x_image (mask_img); - XDestroyImage (ximg); - - return 1; -} - - - -/*********************************************************************** - PBM (mono, gray, color) - ***********************************************************************/ - -static int pbm_image_p P_ ((Lisp_Object object)); -static int pbm_load P_ ((struct frame *f, struct image *img)); -static int pbm_scan_number P_ ((unsigned char **, unsigned char *)); - -/* The symbol `pbm' identifying images of this type. */ - -Lisp_Object Qpbm; - -/* Indices of image specification fields in gs_format, below. */ - -enum pbm_keyword_index -{ - PBM_TYPE, - PBM_FILE, - PBM_DATA, - PBM_ASCENT, - PBM_MARGIN, - PBM_RELIEF, - PBM_ALGORITHM, - PBM_HEURISTIC_MASK, - PBM_MASK, - PBM_FOREGROUND, - PBM_BACKGROUND, - PBM_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid user-defined image specifications. */ - -static struct image_keyword pbm_format[PBM_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":file", IMAGE_STRING_VALUE, 0}, - {":data", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 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_OR_NIL_VALUE, 0}, - {":background", IMAGE_STRING_OR_NIL_VALUE, 0} -}; - -/* Structure describing the image type `pbm'. */ - -static struct image_type pbm_type = -{ - &Qpbm, - pbm_image_p, - pbm_load, - x_clear_image, - NULL -}; - - -/* Return non-zero if OBJECT is a valid PBM image specification. */ - -static int -pbm_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[PBM_LAST]; - - bcopy (pbm_format, fmt, sizeof fmt); - - if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)) - return 0; - - /* Must specify either :data or :file. */ - return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1; -} - - -/* Scan a decimal number from *S and return it. Advance *S while - reading the number. END is the end of the string. Value is -1 at - end of input. */ - -static int -pbm_scan_number (s, end) - unsigned char **s, *end; -{ - int c = 0, val = -1; - - while (*s < end) - { - /* Skip white-space. */ - while (*s < end && (c = *(*s)++, isspace (c))) - ; - - if (c == '#') - { - /* Skip comment to end of line. */ - while (*s < end && (c = *(*s)++, c != '\n')) - ; - } - else if (isdigit (c)) - { - /* Read decimal number. */ - val = c - '0'; - while (*s < end && (c = *(*s)++, isdigit (c))) - val = 10 * val + c - '0'; - break; - } - else - break; - } - - return val; -} - - -/* Load PBM image IMG for use on frame F. */ - -static int -pbm_load (f, img) - struct frame *f; - struct image *img; -{ - int raw_p, x, y; - int width, height, max_color_idx = 0; - XImage *ximg; - Lisp_Object file, specified_file; - enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type; - struct gcpro gcpro1; - unsigned char *contents = NULL; - unsigned char *end, *p; - int size; - - specified_file = image_spec_value (img->spec, QCfile, NULL); - file = Qnil; - GCPRO1 (file); - - if (STRINGP (specified_file)) - { - file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNGCPRO; - return 0; - } - - contents = slurp_file (SDATA (file), &size); - if (contents == NULL) - { - image_error ("Error reading `%s'", file, Qnil); - UNGCPRO; - return 0; - } - - p = contents; - end = contents + size; - } - else - { - Lisp_Object data; - data = image_spec_value (img->spec, QCdata, NULL); - p = SDATA (data); - end = p + SBYTES (data); - } - - /* Check magic number. */ - if (end - p < 2 || *p++ != 'P') - { - image_error ("Not a PBM image: `%s'", img->spec, Qnil); - error: - xfree (contents); - UNGCPRO; - return 0; - } - - switch (*p++) - { - case '1': - raw_p = 0, type = PBM_MONO; - break; - - case '2': - raw_p = 0, type = PBM_GRAY; - break; - - case '3': - raw_p = 0, type = PBM_COLOR; - break; - - case '4': - raw_p = 1, type = PBM_MONO; - break; - - case '5': - raw_p = 1, type = PBM_GRAY; - break; - - case '6': - raw_p = 1, type = PBM_COLOR; - break; - - default: - image_error ("Not a PBM image: `%s'", img->spec, Qnil); - goto error; - } - - /* Read width, height, maximum color-component. Characters - starting with `#' up to the end of a line are ignored. */ - width = pbm_scan_number (&p, end); - height = pbm_scan_number (&p, end); - - if (type != PBM_MONO) - { - max_color_idx = pbm_scan_number (&p, end); - if (raw_p && max_color_idx > 255) - max_color_idx = 255; - } - - if (width < 0 - || height < 0 - || (type != PBM_MONO && max_color_idx < 0)) - goto error; - - if (!x_create_x_image_and_pixmap (f, width, height, 0, - &ximg, &img->pixmap)) - goto error; - - /* Initialize the color hash table. */ - init_color_table (); - - 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 - && STRINGP (fmt[PBM_FOREGROUND].value)) - fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg); - if (fmt[PBM_BACKGROUND].count - && STRINGP (fmt[PBM_BACKGROUND].value)) - { - bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg); - img->background = bg; - img->background_valid = 1; - } - - for (y = 0; y < height; ++y) - for (x = 0; x < width; ++x) - { - if (raw_p) - { - if ((x & 7) == 0) - c = *p++; - g = c & 0x80; - c <<= 1; - } - else - g = pbm_scan_number (&p, end); - - XPutPixel (ximg, x, y, g ? fg : bg); - } - } - else - { - for (y = 0; y < height; ++y) - for (x = 0; x < width; ++x) - { - int r, g, b; - - if (type == PBM_GRAY) - r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end); - else if (raw_p) - { - r = *p++; - g = *p++; - b = *p++; - } - else - { - r = pbm_scan_number (&p, end); - g = pbm_scan_number (&p, end); - b = pbm_scan_number (&p, end); - } - - if (r < 0 || g < 0 || b < 0) - { - xfree (ximg->data); - ximg->data = NULL; - XDestroyImage (ximg); - image_error ("Invalid pixel value in image `%s'", - img->spec, Qnil); - goto error; - } - - /* RGB values are now in the range 0..max_color_idx. - Scale this to the range 0..0xffff supported by X. */ - r = (double) r * 65535 / max_color_idx; - g = (double) g * 65535 / max_color_idx; - b = (double) b * 65535 / max_color_idx; - XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b)); - } - } - - /* Store in IMG->colors the colors allocated for the image, and - free the color table. */ - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); - - /* Maybe fill in the background field while we have ximg handy. */ - if (NILP (image_spec_value (img->spec, QCbackground, NULL))) - IMAGE_BACKGROUND (img, f, ximg); - - /* Put the image into a pixmap. */ - x_put_x_image (f, ximg, img->pixmap, width, height); - x_destroy_x_image (ximg); - - img->width = width; - img->height = height; - - UNGCPRO; - xfree (contents); - return 1; -} - - - -/*********************************************************************** - PNG - ***********************************************************************/ - -#if HAVE_PNG - -#if defined HAVE_LIBPNG_PNG_H -# include <libpng/png.h> -#else -# include <png.h> -#endif - -/* Function prototypes. */ - -static int png_image_p P_ ((Lisp_Object object)); -static int png_load P_ ((struct frame *f, struct image *img)); - -/* The symbol `png' identifying images of this type. */ - -Lisp_Object Qpng; - -/* Indices of image specification fields in png_format, below. */ - -enum png_keyword_index -{ - PNG_TYPE, - PNG_DATA, - PNG_FILE, - PNG_ASCENT, - PNG_MARGIN, - PNG_RELIEF, - PNG_ALGORITHM, - PNG_HEURISTIC_MASK, - PNG_MASK, - PNG_BACKGROUND, - PNG_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid user-defined image specifications. */ - -static struct image_keyword png_format[PNG_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":data", IMAGE_STRING_VALUE, 0}, - {":file", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 0}, - {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":background", IMAGE_STRING_OR_NIL_VALUE, 0} -}; - -/* Structure describing the image type `png'. */ - -static struct image_type png_type = -{ - &Qpng, - png_image_p, - png_load, - x_clear_image, - NULL -}; - - -/* Return non-zero if OBJECT is a valid PNG image specification. */ - -static int -png_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[PNG_LAST]; - bcopy (png_format, fmt, sizeof fmt); - - if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)) - return 0; - - /* Must specify either the :data or :file keyword. */ - return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1; -} - - -/* Error and warning handlers installed when the PNG library - is initialized. */ - -static void -my_png_error (png_ptr, msg) - png_struct *png_ptr; - char *msg; -{ - xassert (png_ptr != NULL); - image_error ("PNG error: %s", build_string (msg), Qnil); - longjmp (png_ptr->jmpbuf, 1); -} - - -static void -my_png_warning (png_ptr, msg) - png_struct *png_ptr; - char *msg; -{ - xassert (png_ptr != NULL); - image_error ("PNG warning: %s", build_string (msg), Qnil); -} - -/* Memory source for PNG decoding. */ - -struct png_memory_storage -{ - unsigned char *bytes; /* The data */ - size_t len; /* How big is it? */ - int index; /* Where are we? */ -}; - - -/* Function set as reader function when reading PNG image from memory. - PNG_PTR is a pointer to the PNG control structure. Copy LENGTH - bytes from the input to DATA. */ - -static void -png_read_from_memory (png_ptr, data, length) - png_structp png_ptr; - png_bytep data; - png_size_t length; -{ - struct png_memory_storage *tbr - = (struct png_memory_storage *) png_get_io_ptr (png_ptr); - - if (length > tbr->len - tbr->index) - png_error (png_ptr, "Read error"); - - bcopy (tbr->bytes + tbr->index, data, length); - tbr->index = tbr->index + length; -} - -/* Load PNG image IMG for use on frame F. Value is non-zero if - successful. */ - -static int -png_load (f, img) - struct frame *f; - struct image *img; -{ - Lisp_Object file, specified_file; - Lisp_Object specified_data; - int x, y, i; - XImage *ximg, *mask_img = NULL; - struct gcpro gcpro1; - png_struct *png_ptr = NULL; - png_info *info_ptr = NULL, *end_info = NULL; - FILE *volatile fp = NULL; - png_byte sig[8]; - png_byte * volatile pixels = NULL; - png_byte ** volatile rows = NULL; - png_uint_32 width, height; - int bit_depth, color_type, interlace_type; - png_byte channels; - png_uint_32 row_bytes; - int transparent_p; - double screen_gamma; - struct png_memory_storage tbr; /* Data to be read */ - - /* Find out what file to load. */ - specified_file = image_spec_value (img->spec, QCfile, NULL); - specified_data = image_spec_value (img->spec, QCdata, NULL); - file = Qnil; - GCPRO1 (file); - - if (NILP (specified_data)) - { - file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNGCPRO; - return 0; - } - - /* Open the image file. */ - fp = fopen (SDATA (file), "rb"); - if (!fp) - { - image_error ("Cannot open image file `%s'", file, Qnil); - UNGCPRO; - fclose (fp); - return 0; - } - - /* Check PNG signature. */ - if (fread (sig, 1, sizeof sig, fp) != sizeof sig - || !png_check_sig (sig, sizeof sig)) - { - image_error ("Not a PNG file: `%s'", file, Qnil); - UNGCPRO; - fclose (fp); - return 0; - } - } - else - { - /* Read from memory. */ - tbr.bytes = SDATA (specified_data); - tbr.len = SBYTES (specified_data); - tbr.index = 0; - - /* Check PNG signature. */ - if (tbr.len < sizeof sig - || !png_check_sig (tbr.bytes, sizeof sig)) - { - image_error ("Not a PNG image: `%s'", img->spec, Qnil); - UNGCPRO; - return 0; - } - - /* Need to skip past the signature. */ - tbr.bytes += sizeof (sig); - } - - /* Initialize read and info structs for PNG lib. */ - png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, - my_png_error, my_png_warning); - if (!png_ptr) - { - if (fp) fclose (fp); - UNGCPRO; - return 0; - } - - info_ptr = png_create_info_struct (png_ptr); - if (!info_ptr) - { - png_destroy_read_struct (&png_ptr, NULL, NULL); - if (fp) fclose (fp); - UNGCPRO; - return 0; - } - - end_info = png_create_info_struct (png_ptr); - if (!end_info) - { - png_destroy_read_struct (&png_ptr, &info_ptr, NULL); - if (fp) fclose (fp); - UNGCPRO; - return 0; - } - - /* Set error jump-back. We come back here when the PNG library - detects an error. */ - if (setjmp (png_ptr->jmpbuf)) - { - error: - if (png_ptr) - png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); - xfree (pixels); - xfree (rows); - if (fp) fclose (fp); - UNGCPRO; - return 0; - } - - /* Read image info. */ - if (!NILP (specified_data)) - png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory); - else - png_init_io (png_ptr, fp); - - png_set_sig_bytes (png_ptr, sizeof sig); - png_read_info (png_ptr, info_ptr); - png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, - &interlace_type, NULL, NULL); - - /* If image contains simply transparency data, we prefer to - construct a clipping mask. */ - if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) - transparent_p = 1; - else - transparent_p = 0; - - /* This function is easier to write if we only have to handle - one data format: RGB or RGBA with 8 bits per channel. Let's - transform other formats into that format. */ - - /* Strip more than 8 bits per channel. */ - if (bit_depth == 16) - png_set_strip_16 (png_ptr); - - /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel - if available. */ - png_set_expand (png_ptr); - - /* Convert grayscale images to RGB. */ - if (color_type == PNG_COLOR_TYPE_GRAY - || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb (png_ptr); - - screen_gamma = (f->gamma ? 1 / f->gamma / 0.45455 : 2.2); - -#if 0 /* Avoid double gamma correction for PNG images. */ - { /* Tell the PNG lib to handle gamma correction for us. */ - int intent; - double image_gamma; -#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED) - if (png_get_sRGB (png_ptr, info_ptr, &intent)) - /* The libpng documentation says this is right in this case. */ - png_set_gamma (png_ptr, screen_gamma, 0.45455); - else -#endif - if (png_get_gAMA (png_ptr, info_ptr, &image_gamma)) - /* Image contains gamma information. */ - png_set_gamma (png_ptr, screen_gamma, image_gamma); - else - /* Use the standard default for the image gamma. */ - png_set_gamma (png_ptr, screen_gamma, 0.45455); - } -#endif /* if 0 */ - - /* Handle alpha channel by combining the image with a background - color. Do this only if a real alpha channel is supplied. For - simple transparency, we prefer a clipping mask. */ - if (!transparent_p) - { - png_color_16 *image_bg; - Lisp_Object specified_bg - = image_spec_value (img->spec, QCbackground, NULL); - - if (STRINGP (specified_bg)) - /* The user specified `:background', use that. */ - { - XColor color; - if (x_defined_color (f, SDATA (specified_bg), &color, 0)) - { - png_color_16 user_bg; - - bzero (&user_bg, sizeof user_bg); - user_bg.red = color.red; - user_bg.green = color.green; - user_bg.blue = color.blue; - - png_set_background (png_ptr, &user_bg, - PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); - } - } - else if (png_get_bKGD (png_ptr, info_ptr, &image_bg)) - /* Image contains a background color with which to - combine the image. */ - png_set_background (png_ptr, image_bg, - PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); - else - { - /* Image does not contain a background color with which - to combine the image data via an alpha channel. Use - the frame's background instead. */ - XColor color; - Colormap cmap; - png_color_16 frame_background; - - cmap = FRAME_X_COLORMAP (f); - color.pixel = FRAME_BACKGROUND_PIXEL (f); - x_query_color (f, &color); - - bzero (&frame_background, sizeof frame_background); - frame_background.red = color.red; - frame_background.green = color.green; - frame_background.blue = color.blue; - - png_set_background (png_ptr, &frame_background, - PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); - } - } - - /* Update info structure. */ - png_read_update_info (png_ptr, info_ptr); - - /* Get number of channels. Valid values are 1 for grayscale images - and images with a palette, 2 for grayscale images with transparency - information (alpha channel), 3 for RGB images, and 4 for RGB - images with alpha channel, i.e. RGBA. If conversions above were - sufficient we should only have 3 or 4 channels here. */ - channels = png_get_channels (png_ptr, info_ptr); - xassert (channels == 3 || channels == 4); - - /* Number of bytes needed for one row of the image. */ - row_bytes = png_get_rowbytes (png_ptr, info_ptr); - - /* Allocate memory for the image. */ - pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels); - rows = (png_byte **) xmalloc (height * sizeof *rows); - for (i = 0; i < height; ++i) - rows[i] = pixels + i * row_bytes; - - /* Read the entire image. */ - png_read_image (png_ptr, rows); - png_read_end (png_ptr, info_ptr); - if (fp) - { - fclose (fp); - fp = NULL; - } - - /* Create the X image and pixmap. */ - if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, - &img->pixmap)) - goto error; - - /* Create an image and pixmap serving as mask if the PNG image - contains an alpha channel. */ - if (channels == 4 - && !transparent_p - && !x_create_x_image_and_pixmap (f, width, height, 1, - &mask_img, &img->mask)) - { - x_destroy_x_image (ximg); - XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap); - img->pixmap = None; - goto error; - } - - /* Fill the X image and mask from PNG data. */ - init_color_table (); - - for (y = 0; y < height; ++y) - { - png_byte *p = rows[y]; - - for (x = 0; x < width; ++x) - { - unsigned r, g, b; - - r = *p++ << 8; - g = *p++ << 8; - b = *p++ << 8; - XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b)); - - /* An alpha channel, aka mask channel, associates variable - transparency with an image. Where other image formats - support binary transparency---fully transparent or fully - opaque---PNG allows up to 254 levels of partial transparency. - The PNG library implements partial transparency by combining - the image with a specified background color. - - I'm not sure how to handle this here nicely: because the - background on which the image is displayed may change, for - real alpha channel support, it would be necessary to create - a new image for each possible background. - - What I'm doing now is that a mask is created if we have - boolean transparency information. Otherwise I'm using - the frame's background color to combine the image with. */ - - if (channels == 4) - { - if (mask_img) - XPutPixel (mask_img, x, y, *p > 0); - ++p; - } - } - } - - if (NILP (image_spec_value (img->spec, QCbackground, NULL))) - /* Set IMG's background color from the PNG image, unless the user - overrode it. */ - { - png_color_16 *bg; - if (png_get_bKGD (png_ptr, info_ptr, &bg)) - { - img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue); - img->background_valid = 1; - } - } - - /* Remember colors allocated for this image. */ - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); - - /* Clean up. */ - png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); - xfree (rows); - xfree (pixels); - - img->width = width; - img->height = height; - - /* Maybe fill in the background field while we have ximg handy. */ - IMAGE_BACKGROUND (img, f, ximg); - - /* Put the image into the pixmap, then free the X image and its buffer. */ - x_put_x_image (f, ximg, img->pixmap, width, height); - x_destroy_x_image (ximg); - - /* Same for the mask. */ - if (mask_img) - { - /* Fill in the background_transparent field while we have the mask - handy. */ - image_background_transparent (img, f, mask_img); - - x_put_x_image (f, mask_img, img->mask, img->width, img->height); - x_destroy_x_image (mask_img); - } - - UNGCPRO; - return 1; -} - -#endif /* HAVE_PNG != 0 */ - - - -/*********************************************************************** - JPEG - ***********************************************************************/ - -#if HAVE_JPEG - -/* Work around a warning about HAVE_STDLIB_H being redefined in - jconfig.h. */ -#ifdef HAVE_STDLIB_H -#define HAVE_STDLIB_H_1 -#undef HAVE_STDLIB_H -#endif /* HAVE_STLIB_H */ - -#include <jpeglib.h> -#include <jerror.h> -#include <setjmp.h> - -#ifdef HAVE_STLIB_H_1 -#define HAVE_STDLIB_H 1 -#endif - -static int jpeg_image_p P_ ((Lisp_Object object)); -static int jpeg_load P_ ((struct frame *f, struct image *img)); - -/* The symbol `jpeg' identifying images of this type. */ - -Lisp_Object Qjpeg; - -/* Indices of image specification fields in gs_format, below. */ - -enum jpeg_keyword_index -{ - JPEG_TYPE, - JPEG_DATA, - JPEG_FILE, - JPEG_ASCENT, - JPEG_MARGIN, - JPEG_RELIEF, - JPEG_ALGORITHM, - JPEG_HEURISTIC_MASK, - JPEG_MASK, - JPEG_BACKGROUND, - JPEG_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid user-defined image specifications. */ - -static struct image_keyword jpeg_format[JPEG_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":data", IMAGE_STRING_VALUE, 0}, - {":file", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 0}, - {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":background", IMAGE_STRING_OR_NIL_VALUE, 0} -}; - -/* Structure describing the image type `jpeg'. */ -static struct image_type jpeg_type = -{ - &Qjpeg, - jpeg_image_p, - jpeg_load, - x_clear_image, - NULL -}; - - -/* Return non-zero if OBJECT is a valid JPEG image specification. */ - -static int -jpeg_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[JPEG_LAST]; - - bcopy (jpeg_format, fmt, sizeof fmt); - - if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)) - return 0; - - /* Must specify either the :data or :file keyword. */ - return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1; -} - - -struct my_jpeg_error_mgr -{ - struct jpeg_error_mgr pub; - jmp_buf setjmp_buffer; -}; - - -static void -my_error_exit (cinfo) - j_common_ptr cinfo; -{ - struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err; - longjmp (mgr->setjmp_buffer, 1); -} - - -/* Init source method for JPEG data source manager. Called by - jpeg_read_header() before any data is actually read. See - libjpeg.doc from the JPEG lib distribution. */ - -static void -our_init_source (cinfo) - j_decompress_ptr cinfo; -{ -} - - -/* Fill input buffer method for JPEG data source manager. Called - whenever more data is needed. We read the whole image in one step, - so this only adds a fake end of input marker at the end. */ - -static boolean -our_fill_input_buffer (cinfo) - j_decompress_ptr cinfo; -{ - /* Insert a fake EOI marker. */ - struct jpeg_source_mgr *src = cinfo->src; - static JOCTET buffer[2]; - - buffer[0] = (JOCTET) 0xFF; - buffer[1] = (JOCTET) JPEG_EOI; - - src->next_input_byte = buffer; - src->bytes_in_buffer = 2; - return TRUE; -} - - -/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src - is the JPEG data source manager. */ - -static void -our_skip_input_data (cinfo, num_bytes) - j_decompress_ptr cinfo; - long num_bytes; -{ - struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src; - - if (src) - { - if (num_bytes > src->bytes_in_buffer) - ERREXIT (cinfo, JERR_INPUT_EOF); - - src->bytes_in_buffer -= num_bytes; - src->next_input_byte += num_bytes; - } -} - - -/* Method to terminate data source. Called by - jpeg_finish_decompress() after all data has been processed. */ - -static void -our_term_source (cinfo) - j_decompress_ptr cinfo; -{ -} - - -/* Set up the JPEG lib for reading an image from DATA which contains - LEN bytes. CINFO is the decompression info structure created for - reading the image. */ - -static void -jpeg_memory_src (cinfo, data, len) - j_decompress_ptr cinfo; - JOCTET *data; - unsigned int len; -{ - struct jpeg_source_mgr *src; - - if (cinfo->src == NULL) - { - /* First time for this JPEG object? */ - cinfo->src = (struct jpeg_source_mgr *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - sizeof (struct jpeg_source_mgr)); - src = (struct jpeg_source_mgr *) cinfo->src; - src->next_input_byte = data; - } - - src = (struct jpeg_source_mgr *) cinfo->src; - src->init_source = our_init_source; - src->fill_input_buffer = our_fill_input_buffer; - src->skip_input_data = our_skip_input_data; - src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */ - src->term_source = our_term_source; - src->bytes_in_buffer = len; - src->next_input_byte = data; -} - - -/* Load image IMG for use on frame F. Patterned after example.c - from the JPEG lib. */ - -static int -jpeg_load (f, img) - struct frame *f; - struct image *img; -{ - struct jpeg_decompress_struct cinfo; - struct my_jpeg_error_mgr mgr; - Lisp_Object file, specified_file; - Lisp_Object specified_data; - FILE * volatile fp = NULL; - JSAMPARRAY buffer; - int row_stride, x, y; - XImage *ximg = NULL; - int rc; - unsigned long *colors; - int width, height; - struct gcpro gcpro1; - - /* Open the JPEG file. */ - specified_file = image_spec_value (img->spec, QCfile, NULL); - specified_data = image_spec_value (img->spec, QCdata, NULL); - file = Qnil; - GCPRO1 (file); - - if (NILP (specified_data)) - { - file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNGCPRO; - return 0; - } - - fp = fopen (SDATA (file), "r"); - if (fp == NULL) - { - image_error ("Cannot open `%s'", file, Qnil); - UNGCPRO; - return 0; - } - } - - /* Customize libjpeg's error handling to call my_error_exit when an - error is detected. This function will perform a longjmp. */ - cinfo.err = jpeg_std_error (&mgr.pub); - mgr.pub.error_exit = my_error_exit; - - if ((rc = setjmp (mgr.setjmp_buffer)) != 0) - { - if (rc == 1) - { - /* Called from my_error_exit. Display a JPEG error. */ - char buffer[JMSG_LENGTH_MAX]; - cinfo.err->format_message ((j_common_ptr) &cinfo, buffer); - image_error ("Error reading JPEG image `%s': %s", img->spec, - build_string (buffer)); - } - - /* Close the input file and destroy the JPEG object. */ - if (fp) - fclose ((FILE *) fp); - jpeg_destroy_decompress (&cinfo); - - /* If we already have an XImage, free that. */ - x_destroy_x_image (ximg); - - /* Free pixmap and colors. */ - x_clear_image (f, img); - - UNGCPRO; - return 0; - } - - /* Create the JPEG decompression object. Let it read from fp. - Read the JPEG image header. */ - jpeg_create_decompress (&cinfo); - - if (NILP (specified_data)) - jpeg_stdio_src (&cinfo, (FILE *) fp); - else - jpeg_memory_src (&cinfo, SDATA (specified_data), - SBYTES (specified_data)); - - jpeg_read_header (&cinfo, TRUE); - - /* Customize decompression so that color quantization will be used. - Start decompression. */ - cinfo.quantize_colors = TRUE; - jpeg_start_decompress (&cinfo); - width = img->width = cinfo.output_width; - height = img->height = cinfo.output_height; - - /* Create X image and pixmap. */ - if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) - longjmp (mgr.setjmp_buffer, 2); - - /* Allocate colors. When color quantization is used, - cinfo.actual_number_of_colors has been set with the number of - colors generated, and cinfo.colormap is a two-dimensional array - of color indices in the range 0..cinfo.actual_number_of_colors. - No more than 255 colors will be generated. */ - { - int i, ir, ig, ib; - - if (cinfo.out_color_components > 2) - ir = 0, ig = 1, ib = 2; - else if (cinfo.out_color_components > 1) - ir = 0, ig = 1, ib = 0; - else - ir = 0, ig = 0, ib = 0; - - /* Use the color table mechanism because it handles colors that - cannot be allocated nicely. Such colors will be replaced with - a default color, and we don't have to care about which colors - can be freed safely, and which can't. */ - init_color_table (); - colors = (unsigned long *) alloca (cinfo.actual_number_of_colors - * sizeof *colors); - - for (i = 0; i < cinfo.actual_number_of_colors; ++i) - { - /* Multiply RGB values with 255 because X expects RGB values - in the range 0..0xffff. */ - int r = cinfo.colormap[ir][i] << 8; - int g = cinfo.colormap[ig][i] << 8; - int b = cinfo.colormap[ib][i] << 8; - colors[i] = lookup_rgb_color (f, r, g, b); - } - - /* Remember those colors actually allocated. */ - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); - } - - /* Read pixels. */ - row_stride = width * cinfo.output_components; - buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE, - row_stride, 1); - for (y = 0; y < height; ++y) - { - jpeg_read_scanlines (&cinfo, buffer, 1); - for (x = 0; x < cinfo.output_width; ++x) - XPutPixel (ximg, x, y, colors[buffer[0][x]]); - } - - /* Clean up. */ - jpeg_finish_decompress (&cinfo); - jpeg_destroy_decompress (&cinfo); - if (fp) - fclose ((FILE *) fp); - - /* Maybe fill in the background field while we have ximg handy. */ - if (NILP (image_spec_value (img->spec, QCbackground, NULL))) - IMAGE_BACKGROUND (img, f, ximg); - - /* Put the image into the pixmap. */ - x_put_x_image (f, ximg, img->pixmap, width, height); - x_destroy_x_image (ximg); - UNGCPRO; - return 1; -} - -#endif /* HAVE_JPEG */ - - - -/*********************************************************************** - TIFF - ***********************************************************************/ - -#if HAVE_TIFF - -#include <tiffio.h> - -static int tiff_image_p P_ ((Lisp_Object object)); -static int tiff_load P_ ((struct frame *f, struct image *img)); - -/* The symbol `tiff' identifying images of this type. */ - -Lisp_Object Qtiff; - -/* Indices of image specification fields in tiff_format, below. */ - -enum tiff_keyword_index -{ - TIFF_TYPE, - TIFF_DATA, - TIFF_FILE, - TIFF_ASCENT, - TIFF_MARGIN, - TIFF_RELIEF, - TIFF_ALGORITHM, - TIFF_HEURISTIC_MASK, - TIFF_MASK, - TIFF_BACKGROUND, - TIFF_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid user-defined image specifications. */ - -static struct image_keyword tiff_format[TIFF_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":data", IMAGE_STRING_VALUE, 0}, - {":file", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 0}, - {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":background", IMAGE_STRING_OR_NIL_VALUE, 0} -}; - -/* Structure describing the image type `tiff'. */ - -static struct image_type tiff_type = -{ - &Qtiff, - tiff_image_p, - tiff_load, - x_clear_image, - NULL -}; - - -/* Return non-zero if OBJECT is a valid TIFF image specification. */ - -static int -tiff_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[TIFF_LAST]; - bcopy (tiff_format, fmt, sizeof fmt); - - if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)) - return 0; - - /* Must specify either the :data or :file keyword. */ - return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1; -} - - -/* Reading from a memory buffer for TIFF images Based on the PNG - memory source, but we have to provide a lot of extra functions. - Blah. - - We really only need to implement read and seek, but I am not - convinced that the TIFF library is smart enough not to destroy - itself if we only hand it the function pointers we need to - override. */ - -typedef struct -{ - unsigned char *bytes; - size_t len; - int index; -} -tiff_memory_source; - - -static size_t -tiff_read_from_memory (data, buf, size) - thandle_t data; - tdata_t buf; - tsize_t size; -{ - tiff_memory_source *src = (tiff_memory_source *) data; - - if (size > src->len - src->index) - return (size_t) -1; - bcopy (src->bytes + src->index, buf, size); - src->index += size; - return size; -} - - -static size_t -tiff_write_from_memory (data, buf, size) - thandle_t data; - tdata_t buf; - tsize_t size; -{ - return (size_t) -1; -} - - -static toff_t -tiff_seek_in_memory (data, off, whence) - thandle_t data; - toff_t off; - int whence; -{ - tiff_memory_source *src = (tiff_memory_source *) data; - int idx; - - switch (whence) - { - case SEEK_SET: /* Go from beginning of source. */ - idx = off; - break; - - case SEEK_END: /* Go from end of source. */ - idx = src->len + off; - break; - - case SEEK_CUR: /* Go from current position. */ - idx = src->index + off; - break; - - default: /* Invalid `whence'. */ - return -1; - } - - if (idx > src->len || idx < 0) - return -1; - - src->index = idx; - return src->index; -} - - -static int -tiff_close_memory (data) - thandle_t data; -{ - /* NOOP */ - return 0; -} - - -static int -tiff_mmap_memory (data, pbase, psize) - thandle_t data; - tdata_t *pbase; - toff_t *psize; -{ - /* It is already _IN_ memory. */ - return 0; -} - - -static void -tiff_unmap_memory (data, base, size) - thandle_t data; - tdata_t base; - toff_t size; -{ - /* We don't need to do this. */ -} - - -static toff_t -tiff_size_of_memory (data) - thandle_t data; -{ - return ((tiff_memory_source *) data)->len; -} - - -static void -tiff_error_handler (title, format, ap) - const char *title, *format; - va_list ap; -{ - char buf[512]; - int len; - - len = sprintf (buf, "TIFF error: %s ", title); - vsprintf (buf + len, format, ap); - add_to_log (buf, Qnil, Qnil); -} - - -static void -tiff_warning_handler (title, format, ap) - const char *title, *format; - va_list ap; -{ - char buf[512]; - int len; - - len = sprintf (buf, "TIFF warning: %s ", title); - vsprintf (buf + len, format, ap); - add_to_log (buf, Qnil, Qnil); -} - - -/* Load TIFF image IMG for use on frame F. Value is non-zero if - successful. */ - -static int -tiff_load (f, img) - struct frame *f; - struct image *img; -{ - Lisp_Object file, specified_file; - Lisp_Object specified_data; - TIFF *tiff; - int width, height, x, y; - uint32 *buf; - int rc; - XImage *ximg; - struct gcpro gcpro1; - tiff_memory_source memsrc; - - specified_file = image_spec_value (img->spec, QCfile, NULL); - specified_data = image_spec_value (img->spec, QCdata, NULL); - file = Qnil; - GCPRO1 (file); - - TIFFSetErrorHandler (tiff_error_handler); - TIFFSetWarningHandler (tiff_warning_handler); - - if (NILP (specified_data)) - { - /* Read from a file */ - file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", file, Qnil); - UNGCPRO; - return 0; - } - - /* Try to open the image file. */ - tiff = TIFFOpen (SDATA (file), "r"); - if (tiff == NULL) - { - image_error ("Cannot open `%s'", file, Qnil); - UNGCPRO; - return 0; - } - } - else - { - /* Memory source! */ - memsrc.bytes = SDATA (specified_data); - memsrc.len = SBYTES (specified_data); - memsrc.index = 0; - - tiff = TIFFClientOpen ("memory_source", "r", &memsrc, - (TIFFReadWriteProc) tiff_read_from_memory, - (TIFFReadWriteProc) tiff_write_from_memory, - tiff_seek_in_memory, - tiff_close_memory, - tiff_size_of_memory, - tiff_mmap_memory, - tiff_unmap_memory); - - if (!tiff) - { - image_error ("Cannot open memory source for `%s'", img->spec, Qnil); - UNGCPRO; - return 0; - } - } - - /* Get width and height of the image, and allocate a raster buffer - of width x height 32-bit values. */ - TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width); - TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height); - buf = (uint32 *) xmalloc (width * height * sizeof *buf); - - rc = TIFFReadRGBAImage (tiff, width, height, buf, 0); - TIFFClose (tiff); - if (!rc) - { - image_error ("Error reading TIFF image `%s'", img->spec, Qnil); - xfree (buf); - UNGCPRO; - return 0; - } - - /* Create the X image and pixmap. */ - if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) - { - xfree (buf); - UNGCPRO; - return 0; - } - - /* Initialize the color table. */ - init_color_table (); - - /* Process the pixel raster. Origin is in the lower-left corner. */ - for (y = 0; y < height; ++y) - { - uint32 *row = buf + y * width; - - for (x = 0; x < width; ++x) - { - uint32 abgr = row[x]; - int r = TIFFGetR (abgr) << 8; - int g = TIFFGetG (abgr) << 8; - int b = TIFFGetB (abgr) << 8; - XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b)); - } - } - - /* Remember the colors allocated for the image. Free the color table. */ - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); - - img->width = width; - img->height = height; - - /* Maybe fill in the background field while we have ximg handy. */ - if (NILP (image_spec_value (img->spec, QCbackground, NULL))) - IMAGE_BACKGROUND (img, f, ximg); - - /* Put the image into the pixmap, then free the X image and its buffer. */ - x_put_x_image (f, ximg, img->pixmap, width, height); - x_destroy_x_image (ximg); - xfree (buf); - - UNGCPRO; - return 1; -} - -#endif /* HAVE_TIFF != 0 */ - - - -/*********************************************************************** - GIF - ***********************************************************************/ - -#if HAVE_GIF - -#include <gif_lib.h> - -static int gif_image_p P_ ((Lisp_Object object)); -static int gif_load P_ ((struct frame *f, struct image *img)); - -/* The symbol `gif' identifying images of this type. */ - -Lisp_Object Qgif; - -/* Indices of image specification fields in gif_format, below. */ - -enum gif_keyword_index -{ - GIF_TYPE, - GIF_DATA, - GIF_FILE, - GIF_ASCENT, - GIF_MARGIN, - GIF_RELIEF, - GIF_ALGORITHM, - GIF_HEURISTIC_MASK, - GIF_MASK, - GIF_IMAGE, - GIF_BACKGROUND, - GIF_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid user-defined image specifications. */ - -static struct image_keyword gif_format[GIF_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":data", IMAGE_STRING_VALUE, 0}, - {":file", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 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}, - {":background", IMAGE_STRING_OR_NIL_VALUE, 0} -}; - -/* Structure describing the image type `gif'. */ - -static struct image_type gif_type = -{ - &Qgif, - gif_image_p, - gif_load, - x_clear_image, - NULL -}; - - -/* Return non-zero if OBJECT is a valid GIF image specification. */ - -static int -gif_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[GIF_LAST]; - bcopy (gif_format, fmt, sizeof fmt); - - if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)) - return 0; - - /* Must specify either the :data or :file keyword. */ - return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1; -} - - -/* Reading a GIF image from memory - Based on the PNG memory stuff to a certain extent. */ - -typedef struct -{ - unsigned char *bytes; - size_t len; - int index; -} -gif_memory_source; - - -/* Make the current memory source available to gif_read_from_memory. - It's done this way because not all versions of libungif support - a UserData field in the GifFileType structure. */ -static gif_memory_source *current_gif_memory_src; - -static int -gif_read_from_memory (file, buf, len) - GifFileType *file; - GifByteType *buf; - int len; -{ - gif_memory_source *src = current_gif_memory_src; - - if (len > src->len - src->index) - return -1; - - bcopy (src->bytes + src->index, buf, len); - src->index += len; - return len; -} - - -/* Load GIF image IMG for use on frame F. Value is non-zero if - successful. */ - -static int -gif_load (f, img) - struct frame *f; - struct image *img; -{ - Lisp_Object file, specified_file; - Lisp_Object specified_data; - int rc, width, height, x, y, i; - XImage *ximg; - ColorMapObject *gif_color_map; - unsigned long pixel_colors[256]; - GifFileType *gif; - struct gcpro gcpro1; - Lisp_Object image; - int ino, image_left, image_top, image_width, image_height; - gif_memory_source memsrc; - unsigned char *raster; - - specified_file = image_spec_value (img->spec, QCfile, NULL); - specified_data = image_spec_value (img->spec, QCdata, NULL); - file = Qnil; - GCPRO1 (file); - - if (NILP (specified_data)) - { - file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNGCPRO; - return 0; - } - - /* Open the GIF file. */ - gif = DGifOpenFileName (SDATA (file)); - if (gif == NULL) - { - image_error ("Cannot open `%s'", file, Qnil); - UNGCPRO; - return 0; - } - } - else - { - /* Read from memory! */ - current_gif_memory_src = &memsrc; - memsrc.bytes = SDATA (specified_data); - memsrc.len = SBYTES (specified_data); - memsrc.index = 0; - - gif = DGifOpen(&memsrc, gif_read_from_memory); - if (!gif) - { - image_error ("Cannot open memory source `%s'", img->spec, Qnil); - UNGCPRO; - return 0; - } - } - - /* Read entire contents. */ - rc = DGifSlurp (gif); - if (rc == GIF_ERROR) - { - image_error ("Error reading `%s'", img->spec, Qnil); - DGifCloseFile (gif); - UNGCPRO; - return 0; - } - - image = image_spec_value (img->spec, QCindex, NULL); - ino = INTEGERP (image) ? XFASTINT (image) : 0; - if (ino >= gif->ImageCount) - { - image_error ("Invalid image number `%s' in image `%s'", - image, img->spec); - DGifCloseFile (gif); - UNGCPRO; - return 0; - } - - width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width); - height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height); - - /* Create the X image and pixmap. */ - if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) - { - DGifCloseFile (gif); - UNGCPRO; - return 0; - } - - /* Allocate colors. */ - gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap; - if (!gif_color_map) - gif_color_map = gif->SColorMap; - init_color_table (); - bzero (pixel_colors, sizeof pixel_colors); - - for (i = 0; i < gif_color_map->ColorCount; ++i) - { - int r = gif_color_map->Colors[i].Red << 8; - int g = gif_color_map->Colors[i].Green << 8; - int b = gif_color_map->Colors[i].Blue << 8; - pixel_colors[i] = lookup_rgb_color (f, r, g, b); - } - - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); - - /* Clear the part of the screen image that are not covered by - the image from the GIF file. Full animated GIF support - requires more than can be done here (see the gif89 spec, - disposal methods). Let's simply assume that the part - not covered by a sub-image is in the frame's background color. */ - image_top = gif->SavedImages[ino].ImageDesc.Top; - image_left = gif->SavedImages[ino].ImageDesc.Left; - image_width = gif->SavedImages[ino].ImageDesc.Width; - image_height = gif->SavedImages[ino].ImageDesc.Height; - - for (y = 0; y < image_top; ++y) - for (x = 0; x < width; ++x) - XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); - - for (y = image_top + image_height; y < height; ++y) - for (x = 0; x < width; ++x) - XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); - - for (y = image_top; y < image_top + image_height; ++y) - { - for (x = 0; x < image_left; ++x) - XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); - for (x = image_left + image_width; x < width; ++x) - XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); - } - - /* Read the GIF image into the X image. We use a local variable - `raster' here because RasterBits below is a char *, and invites - problems with bytes >= 0x80. */ - raster = (unsigned char *) gif->SavedImages[ino].RasterBits; - - if (gif->SavedImages[ino].ImageDesc.Interlace) - { - static int interlace_start[] = {0, 4, 2, 1}; - static int interlace_increment[] = {8, 8, 4, 2}; - int pass; - int row = interlace_start[0]; - - pass = 0; - - for (y = 0; y < image_height; y++) - { - if (row >= image_height) - { - row = interlace_start[++pass]; - while (row >= image_height) - row = interlace_start[++pass]; - } - - for (x = 0; x < image_width; x++) - { - int i = raster[(y * image_width) + x]; - XPutPixel (ximg, x + image_left, row + image_top, - pixel_colors[i]); - } - - row += interlace_increment[pass]; - } - } - else - { - for (y = 0; y < image_height; ++y) - for (x = 0; x < image_width; ++x) - { - int i = raster[y * image_width + x]; - XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]); - } - } - - DGifCloseFile (gif); - - /* Maybe fill in the background field while we have ximg handy. */ - if (NILP (image_spec_value (img->spec, QCbackground, NULL))) - IMAGE_BACKGROUND (img, f, ximg); - - /* Put the image into the pixmap, then free the X image and its buffer. */ - x_put_x_image (f, ximg, img->pixmap, width, height); - x_destroy_x_image (ximg); - - UNGCPRO; - return 1; -} - -#endif /* HAVE_GIF != 0 */ - - - -/*********************************************************************** - Ghostscript - ***********************************************************************/ - -static int gs_image_p P_ ((Lisp_Object object)); -static int gs_load P_ ((struct frame *f, struct image *img)); -static void gs_clear_image P_ ((struct frame *f, struct image *img)); - -/* The symbol `postscript' identifying images of this type. */ - -Lisp_Object Qpostscript; - -/* Keyword symbols. */ - -Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height; - -/* Indices of image specification fields in gs_format, below. */ - -enum gs_keyword_index -{ - GS_TYPE, - GS_PT_WIDTH, - GS_PT_HEIGHT, - GS_FILE, - GS_LOADER, - GS_BOUNDING_BOX, - GS_ASCENT, - GS_MARGIN, - GS_RELIEF, - GS_ALGORITHM, - GS_HEURISTIC_MASK, - GS_MASK, - GS_BACKGROUND, - GS_LAST -}; - -/* Vector of image_keyword structures describing the format - of valid user-defined image specifications. */ - -static struct image_keyword gs_format[GS_LAST] = -{ - {":type", IMAGE_SYMBOL_VALUE, 1}, - {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1}, - {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1}, - {":file", IMAGE_STRING_VALUE, 1}, - {":loader", IMAGE_FUNCTION_VALUE, 0}, - {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1}, - {":ascent", IMAGE_ASCENT_VALUE, 0}, - {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, - {":relief", IMAGE_INTEGER_VALUE, 0}, - {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":background", IMAGE_STRING_OR_NIL_VALUE, 0} -}; - -/* Structure describing the image type `ghostscript'. */ - -static struct image_type gs_type = -{ - &Qpostscript, - gs_image_p, - gs_load, - gs_clear_image, - NULL -}; - - -/* Free X resources of Ghostscript image IMG which is used on frame F. */ - -static void -gs_clear_image (f, img) - struct frame *f; - struct image *img; -{ - /* IMG->data.ptr_val may contain a recorded colormap. */ - xfree (img->data.ptr_val); - x_clear_image (f, img); -} - - -/* Return non-zero if OBJECT is a valid Ghostscript image - specification. */ - -static int -gs_image_p (object) - Lisp_Object object; -{ - struct image_keyword fmt[GS_LAST]; - Lisp_Object tem; - int i; - - bcopy (gs_format, fmt, sizeof fmt); - - if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)) - return 0; - - /* Bounding box must be a list or vector containing 4 integers. */ - tem = fmt[GS_BOUNDING_BOX].value; - if (CONSP (tem)) - { - for (i = 0; i < 4; ++i, tem = XCDR (tem)) - if (!CONSP (tem) || !INTEGERP (XCAR (tem))) - return 0; - if (!NILP (tem)) - return 0; - } - else if (VECTORP (tem)) - { - if (XVECTOR (tem)->size != 4) - return 0; - for (i = 0; i < 4; ++i) - if (!INTEGERP (XVECTOR (tem)->contents[i])) - return 0; - } - else - return 0; - - return 1; -} - - -/* Load Ghostscript image IMG for use on frame F. Value is non-zero - if successful. */ - -static int -gs_load (f, img) - struct frame *f; - struct image *img; -{ - char buffer[100]; - Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width; - struct gcpro gcpro1, gcpro2; - Lisp_Object frame; - double in_width, in_height; - Lisp_Object pixel_colors = Qnil; - - /* Compute pixel size of pixmap needed from the given size in the - image specification. Sizes in the specification are in pt. 1 pt - = 1/72 in, xdpi and ydpi are stored in the frame's X display - info. */ - pt_width = image_spec_value (img->spec, QCpt_width, NULL); - in_width = XFASTINT (pt_width) / 72.0; - img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx; - pt_height = image_spec_value (img->spec, QCpt_height, NULL); - in_height = XFASTINT (pt_height) / 72.0; - img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy; - - /* Create the pixmap. */ - xassert (img->pixmap == None); - img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - img->width, img->height, - DefaultDepthOfScreen (FRAME_X_SCREEN (f))); - - if (!img->pixmap) - { - image_error ("Unable to create pixmap for `%s'", img->spec, Qnil); - return 0; - } - - /* Call the loader to fill the pixmap. It returns a process object - if successful. We do not record_unwind_protect here because - other places in redisplay like calling window scroll functions - don't either. Let the Lisp loader use `unwind-protect' instead. */ - GCPRO2 (window_and_pixmap_id, pixel_colors); - - sprintf (buffer, "%lu %lu", - (unsigned long) FRAME_X_WINDOW (f), - (unsigned long) img->pixmap); - window_and_pixmap_id = build_string (buffer); - - sprintf (buffer, "%lu %lu", - FRAME_FOREGROUND_PIXEL (f), - FRAME_BACKGROUND_PIXEL (f)); - pixel_colors = build_string (buffer); - - XSETFRAME (frame, f); - loader = image_spec_value (img->spec, QCloader, NULL); - if (NILP (loader)) - loader = intern ("gs-load-image"); - - img->data.lisp_val = call6 (loader, frame, img->spec, - make_number (img->width), - make_number (img->height), - window_and_pixmap_id, - pixel_colors); - UNGCPRO; - return PROCESSP (img->data.lisp_val); -} - - -/* Kill the Ghostscript process that was started to fill PIXMAP on - frame F. Called from XTread_socket when receiving an event - telling Emacs that Ghostscript has finished drawing. */ - -void -x_kill_gs_process (pixmap, f) - Pixmap pixmap; - struct frame *f; -{ - struct image_cache *c = FRAME_X_IMAGE_CACHE (f); - int class, i; - struct image *img; - - /* Find the image containing PIXMAP. */ - for (i = 0; i < c->used; ++i) - if (c->images[i]->pixmap == pixmap) - break; - - /* Should someone in between have cleared the image cache, for - instance, give up. */ - if (i == c->used) - return; - - /* Kill the GS process. We should have found PIXMAP in the image - cache and its image should contain a process object. */ - img = c->images[i]; - xassert (PROCESSP (img->data.lisp_val)); - Fkill_process (img->data.lisp_val, Qnil); - img->data.lisp_val = Qnil; - - /* On displays with a mutable colormap, figure out the colors - allocated for the image by looking at the pixels of an XImage for - img->pixmap. */ - class = FRAME_X_VISUAL (f)->class; - if (class != StaticColor && class != StaticGray && class != TrueColor) + BLOCK_INPUT; + prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SDATA (prop), False); + if (! NILP (type)) { - XImage *ximg; - - BLOCK_INPUT; - - /* Try to get an XImage for img->pixmep. */ - ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap, - 0, 0, img->width, img->height, ~0, ZPixmap); - if (ximg) - { - int x, y; - - /* Initialize the color table. */ - init_color_table (); - - /* For each pixel of the image, look its color up in the - color table. After having done so, the color table will - contain an entry for each color used by the image. */ - for (y = 0; y < img->height; ++y) - for (x = 0; x < img->width; ++x) - { - unsigned long pixel = XGetPixel (ximg, x, y); - lookup_pixel_color (f, pixel); - } - - /* Record colors in the image. Free color table and XImage. */ - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); - XDestroyImage (ximg); - -#if 0 /* This doesn't seem to be the case. If we free the colors - here, we get a BadAccess later in x_clear_image when - freeing the colors. */ - /* We have allocated colors once, but Ghostscript has also - allocated colors on behalf of us. So, to get the - reference counts right, free them once. */ - if (img->ncolors) - x_free_colors (f, img->colors, img->ncolors); -#endif - } - else - image_error ("Cannot get X image of `%s'; colors will not be freed", - img->spec, Qnil); - - UNBLOCK_INPUT; + CHECK_STRING (type); + target_type = XInternAtom (FRAME_X_DISPLAY (f), SDATA (type), False); } - /* Now that we have the pixmap, compute mask and transform the - image if requested. */ - BLOCK_INPUT; - postprocess_image (f, img); - UNBLOCK_INPUT; -} - - - -/*********************************************************************** - Window properties - ***********************************************************************/ - -DEFUN ("x-change-window-property", Fx_change_window_property, - Sx_change_window_property, 2, 3, 0, - doc: /* Change window property PROP to VALUE on the X window of FRAME. -PROP and VALUE must be strings. FRAME nil or omitted means use the -selected frame. Value is VALUE. */) - (prop, value, frame) - Lisp_Object frame, prop, value; -{ - struct frame *f = check_x_frame (frame); - Atom prop_atom; - - CHECK_STRING (prop); - CHECK_STRING (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); - BLOCK_INPUT; - prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SDATA (prop), False); - XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - prop_atom, XA_STRING, 8, PropModeReplace, - SDATA (value), SCHARS (value)); + if (CONSP (value)) xfree (data); /* Make sure the property is set when we return. */ XFlush (FRAME_X_DISPLAY (f)); @@ -9456,13 +4052,20 @@ FRAME nil or omitted means use the selected frame. Value is PROP. */) DEFUN ("x-window-property", Fx_window_property, Sx_window_property, - 1, 2, 0, + 1, 6, 0, doc: /* Value is the value of window property PROP on FRAME. -If FRAME is nil or omitted, use the selected frame. Value is nil -if FRAME hasn't a property with name PROP or if PROP has no string -value. */) - (prop, frame) - Lisp_Object prop, frame; +If FRAME is nil or omitted, use the selected frame. +If TYPE is nil or omitted, get the property as a string. Otherwise TYPE +is the name of the Atom that denotes the type expected. +If SOURCE is non-nil, get the property on that window instead of from +FRAME. The number 0 denotes the root window. +If DELETE_P is non-nil, delete the property after retreiving it. +If VECTOR_RET_P is non-nil, don't return a string but a vector of values. + +Value is nil if FRAME hasn't a property with name PROP or if PROP has +no value of TYPE. */) + (prop, frame, type, source, delete_p, vector_ret_p) + Lisp_Object prop, frame, type, source, delete_p, vector_ret_p; { struct frame *f = check_x_frame (frame); Atom prop_atom; @@ -9470,14 +4073,43 @@ value. */) Lisp_Object prop_value = Qnil; char *tmp_data = NULL; Atom actual_type; + Atom target_type = XA_STRING; int actual_format; unsigned long actual_size, bytes_remaining; + Window target_window = FRAME_X_WINDOW (f); + struct gcpro gcpro1; + GCPRO1 (prop_value); CHECK_STRING (prop); + + if (! NILP (source)) + { + if (NUMBERP (source)) + { + if (FLOATP (source)) + target_window = (Window) XFLOAT (source); + else + target_window = XFASTINT (source); + + if (target_window == 0) + target_window = FRAME_X_DISPLAY_INFO (f)->root_window; + } + else if (CONSP (source)) + target_window = cons_to_long (source); + } + BLOCK_INPUT; + if (STRINGP (type)) + { + if (strcmp ("AnyPropertyType", SDATA (type)) == 0) + target_type = AnyPropertyType; + else + target_type = XInternAtom (FRAME_X_DISPLAY (f), SDATA (type), False); + } + prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SDATA (prop), False); - rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - prop_atom, 0, 0, False, XA_STRING, + 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); if (rc == Success) @@ -9487,19 +4119,29 @@ value. */) XFree (tmp_data); tmp_data = NULL; - rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + rc = XGetWindowProperty (FRAME_X_DISPLAY (f), target_window, prop_atom, 0, bytes_remaining, - False, XA_STRING, + ! NILP (delete_p), target_type, &actual_type, &actual_format, &actual_size, &bytes_remaining, (unsigned char **) &tmp_data); if (rc == Success && tmp_data) - prop_value = make_string (tmp_data, size); + { + 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, + actual_type, + actual_format, + actual_size); + } - XFree (tmp_data); + if (tmp_data) XFree (tmp_data); } UNBLOCK_INPUT; + UNGCPRO; return prop_value; } @@ -10551,7 +5193,6 @@ selection dialog's entry field, if MUSTMATCH is non-nil.") int count = specpdl_ptr - specpdl; struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; char *cdef_file; - char *cprompt; GCPRO5 (prompt, dir, default_filename, mustmatch, file); CHECK_STRING (prompt); @@ -10730,8 +5371,6 @@ syms_of_xfns () staticpro (&Qsuppress_icon); Qundefined_color = intern ("undefined-color"); staticpro (&Qundefined_color); - Qcenter = intern ("center"); - staticpro (&Qcenter); Qcompound_text = intern ("compound-text"); staticpro (&Qcompound_text); Qcancel_timer = intern ("cancel-timer"); @@ -10743,36 +5382,11 @@ syms_of_xfns () = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky); - Qlaplace = intern ("laplace"); - staticpro (&Qlaplace); - Qemboss = intern ("emboss"); - staticpro (&Qemboss); - Qedge_detection = intern ("edge-detection"); - staticpro (&Qedge_detection); - Qheuristic = intern ("heuristic"); - staticpro (&Qheuristic); - QCmatrix = intern (":matrix"); - staticpro (&QCmatrix); - QCcolor_adjustment = intern (":color-adjustment"); - staticpro (&QCcolor_adjustment); - QCmask = intern (":mask"); - staticpro (&QCmask); - Fput (Qundefined_color, Qerror_conditions, Fcons (Qundefined_color, Fcons (Qerror, Qnil))); Fput (Qundefined_color, Qerror_message, build_string ("Undefined color")); - DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images, - doc: /* Non-nil means always draw a cross over disabled images. -Disabled images are those having an `:conversion disabled' property. -A cross is always drawn on black & white displays. */); - cross_disabled_images = 0; - - DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path, - doc: /* List of directories to search for window system bitmap files. */); - Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS); - DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape, doc: /* The shape of the pointer when over text. Changing the value does not affect existing frames @@ -10851,13 +5465,6 @@ such a font. This is especially effective for such large fonts as Chinese, Japanese, and Korean. */); Vx_pixel_size_width_font_regexp = Qnil; - DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay, - doc: /* Time after which cached images are removed from the cache. -When an image has not been displayed this many seconds, remove it -from the image cache. Value must be an integer or nil with nil -meaning don't clear the cache. */); - Vimage_cache_eviction_delay = make_number (30 * 60); - #ifdef USE_X_TOOLKIT Fprovide (intern ("x-toolkit"), Qnil); #ifdef USE_MOTIF @@ -10869,6 +5476,19 @@ meaning don't clear the cache. */); #endif /* USE_MOTIF */ #endif /* USE_X_TOOLKIT */ +#ifdef USE_GTK + Fprovide (intern ("gtk"), Qnil); + + DEFVAR_LISP ("gtk-version-string", &Vgtk_version_string, + doc: /* Version info for GTK+. */); + { + char gtk_version[40]; + g_snprintf (gtk_version, sizeof (gtk_version), "%u.%u.%u", + GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION); + Vgtk_version_string = build_string (gtk_version); + } +#endif /* USE_GTK */ + /* X window properties. */ defsubr (&Sx_change_window_property); defsubr (&Sx_delete_window_property); @@ -10914,65 +5534,6 @@ meaning don't clear the cache. */); get_font_repertory_func = x_get_font_repertory; check_window_system_func = check_x; - /* Images. */ - Qxbm = intern ("xbm"); - staticpro (&Qxbm); - QCconversion = intern (":conversion"); - staticpro (&QCconversion); - QCheuristic_mask = intern (":heuristic-mask"); - staticpro (&QCheuristic_mask); - QCcolor_symbols = intern (":color-symbols"); - staticpro (&QCcolor_symbols); - QCascent = intern (":ascent"); - staticpro (&QCascent); - QCmargin = intern (":margin"); - staticpro (&QCmargin); - QCrelief = intern (":relief"); - staticpro (&QCrelief); - Qpostscript = intern ("postscript"); - staticpro (&Qpostscript); - QCloader = intern (":loader"); - staticpro (&QCloader); - QCbounding_box = intern (":bounding-box"); - staticpro (&QCbounding_box); - QCpt_width = intern (":pt-width"); - staticpro (&QCpt_width); - QCpt_height = intern (":pt-height"); - staticpro (&QCpt_height); - QCindex = intern (":index"); - staticpro (&QCindex); - Qpbm = intern ("pbm"); - staticpro (&Qpbm); - -#if HAVE_XPM - Qxpm = intern ("xpm"); - staticpro (&Qxpm); -#endif - -#if HAVE_JPEG - Qjpeg = intern ("jpeg"); - staticpro (&Qjpeg); -#endif - -#if HAVE_TIFF - Qtiff = intern ("tiff"); - staticpro (&Qtiff); -#endif - -#if HAVE_GIF - Qgif = intern ("gif"); - staticpro (&Qgif); -#endif - -#if HAVE_PNG - Qpng = intern ("png"); - staticpro (&Qpng); -#endif - - defsubr (&Sclear_image_cache); - defsubr (&Simage_size); - defsubr (&Simage_mask_p); - hourglass_atimer = NULL; hourglass_shown_p = 0; @@ -10991,36 +5552,7 @@ meaning don't clear the cache. */); #endif } - -void -init_xfns () -{ - image_types = NULL; - Vimage_types = Qnil; - - define_image_type (&xbm_type); - define_image_type (&gs_type); - define_image_type (&pbm_type); - -#if HAVE_XPM - define_image_type (&xpm_type); -#endif - -#if HAVE_JPEG - define_image_type (&jpeg_type); -#endif - -#if HAVE_TIFF - define_image_type (&tiff_type); -#endif - -#if HAVE_GIF - define_image_type (&gif_type); -#endif - -#if HAVE_PNG - define_image_type (&png_type); -#endif -} - #endif /* HAVE_X_WINDOWS */ + +/* arch-tag: 55040d02-5485-4d58-8b22-95a7a05f3288 + (do not change this comment) */ diff --git a/src/xmenu.c b/src/xmenu.c index b46d28626fb..08bad9c2241 100644 --- a/src/xmenu.c +++ b/src/xmenu.c @@ -99,7 +99,6 @@ Lisp_Object Vmenu_updating_frame; Lisp_Object Qdebug_on_next_call; extern Lisp_Object Qmenu_bar; -extern Lisp_Object Qmouse_click, Qevent_kind; extern Lisp_Object QCtoggle, QCradio; @@ -610,7 +609,7 @@ single_menu_item (key, item, dummy, skp_v) #endif /* not HAVE_BOXES */ #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) - if (!NILP(map)) + if (!NILP (map)) /* Indicate visually that this is a submenu. */ item_string = concat2 (item_string, build_string (" >")); #endif @@ -696,7 +695,7 @@ list_of_items (pane) the scroll bar or the edit window. Fx_popup_menu needs to be sure it is the edit window. */ static void -mouse_position_for_popup(f, x, y) +mouse_position_for_popup (f, x, y) FRAME_PTR f; int *x; int *y; @@ -1093,6 +1092,12 @@ on the left of the dialog box and all following items on the right. CHECK_STRING (title); record_unwind_protect (unuse_menu_items, Qnil); + if (NILP (Fcar (Fcdr (contents)))) + /* No buttons specified, add an "Ok" button so users can pop down + the dialog. Also, the lesstif/motif version crashes if there are + no buttons. */ + contents = Fcons (title, Fcons (Fcons (build_string ("Ok"), Qt), Qnil)); + list_of_panes (Fcons (contents, Qnil)); /* Display them in a dialog box. */ @@ -1116,17 +1121,19 @@ on the left of the dialog box and all following items on the right. and x-popup-dialog; it is not used for the menu bar. If DO_TIMERS is nonzero, run timers. + If DOWN_ON_KEYPRESS is nonzero, pop down if a key is pressed. NOTE: All calls to popup_get_selection should be protected with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */ #ifdef USE_X_TOOLKIT static void -popup_get_selection (initial_event, dpyinfo, id, do_timers) +popup_get_selection (initial_event, dpyinfo, id, do_timers, down_on_keypress) XEvent *initial_event; struct x_display_info *dpyinfo; LWLIB_ID id; int do_timers; + int down_on_keypress; { XEvent event; @@ -1162,15 +1169,20 @@ popup_get_selection (initial_event, dpyinfo, id, do_timers) event.xbutton.state = 0; #endif } - /* If the user presses a key, deactivate the menu. + /* If the user presses a key that doesn't go to the menu, + deactivate the menu. The user is likely to do that if we get wedged. - This is mostly for Lucid, Motif pops down the menu on ESC. */ + All toolkits now pop down menus on ESC. + For dialogs however, the focus may not be on the dialog, so + in that case, we pop down. */ else if (event.type == KeyPress + && down_on_keypress && dpyinfo->display == event.xbutton.display) { KeySym keysym = XLookupKeysym (&event.xkey, 0); - if (!IsModifierKey (keysym)) - popup_activated_flag = 0; + if (!IsModifierKey (keysym) + && x_any_window_to_frame (dpyinfo, event.xany.window) != NULL) + popup_activated_flag = 0; } x_dispatch_event (&event, event.xany.display); @@ -1217,7 +1229,8 @@ x_activate_menubar (f) return; #ifdef USE_GTK - if (! xg_win_to_widget (f->output_data.x->saved_menu_event->xany.window)) + if (! xg_win_to_widget (FRAME_X_DISPLAY (f), + f->output_data.x->saved_menu_event->xany.window)) return; #endif @@ -1303,6 +1316,7 @@ show_help_event (f, widget, help) } else { +#if 0 /* This code doesn't do anything useful. ++kfs */ /* WIDGET is the popup menu. It's parent is the frame's widget. See which frame that is. */ xt_or_gtk_widget frame_widget = XtParent (widget); @@ -1316,7 +1330,7 @@ show_help_event (f, widget, help) FRAME_X_P (f) && f->output_data.x->widget == frame_widget)) break; } - +#endif show_help_echo (help, Qnil, Qnil, Qnil, 1); } } @@ -1866,6 +1880,12 @@ set_frame_menubar (f, first_time, deep_p) f->output_data.x->saved_menu_event->type = 0; } +#ifdef USE_GTK + /* If we have detached menus, we must update deep so detached menus + also gets updated. */ + deep_p = deep_p || xg_have_tear_offs (); +#endif + if (deep_p) { /* Make a widget-value tree representing the entire menu trees. */ @@ -2066,7 +2086,7 @@ set_frame_menubar (f, first_time, deep_p) xg_crazy_callback_abort = 1; if (menubar_widget) { - /* The third arg is DEEP_P, which says to consider the entire + /* The fourth arg is DEEP_P, which says to consider the entire menu trees we supply, rather than just the menu bar item names. */ xg_modify_menubar_widgets (menubar_widget, f, @@ -2343,17 +2363,13 @@ create_and_show_popup_menu (f, first_wv, x, y, for_click) gtk_widget_show_all (menu); gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i, 0); - xg_did_tearoff = 0; /* Set this to one. popup_widget_loop increases it by one, so it becomes two. show_help_echo uses this to detect popup menus. */ popup_activated_flag = 1; /* Process events that apply to the menu. */ popup_widget_loop (); - if (xg_did_tearoff) - xg_keep_popup (menu, xg_did_tearoff); - else - gtk_widget_destroy (menu); + gtk_widget_destroy (menu); /* Must reset this manually because the button release event is not passed to Emacs event loop. */ @@ -2439,7 +2455,7 @@ create_and_show_popup_menu (f, first_wv, x, y, for_click) popup_activated_flag = 1; /* Process events that apply to the menu. */ - popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 0); + popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 0, 0); /* fp turned off the following statement and wrote a comment that it is unnecessary--that the menu has already disappeared. @@ -2833,7 +2849,8 @@ create_and_show_dialog (f, first_wv) Fcons (make_number (dialog_id >> (fact)), make_number (dialog_id & ~(-1 << (fact))))); - popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id, 1); + popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), + dialog_id, 1, 1); unbind_to (count, Qnil); } @@ -3376,3 +3393,6 @@ The enable predicate for a menu command should check this variable. */); defsubr (&Sx_popup_dialog); #endif } + +/* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242 + (do not change this comment) */ diff --git a/src/xrdb.c b/src/xrdb.c index 87c8f4b285d..ed701c64c63 100644 --- a/src/xrdb.c +++ b/src/xrdb.c @@ -812,3 +812,6 @@ main (argc, argv) XCloseDisplay (display); } #endif /* TESTRM */ + +/* arch-tag: 37e6fbab-ed05-4363-9e76-6c4109ed511f + (do not change this comment) */ diff --git a/src/xselect.c b/src/xselect.c index 21b7ecff8ab..b4d61f7c9a9 100644 --- a/src/xselect.c +++ b/src/xselect.c @@ -23,6 +23,7 @@ Boston, MA 02111-1307, USA. */ /* Rewritten by jwz */ #include <config.h> +#include <stdio.h> /* termhooks.h needs this */ #include "lisp.h" #include "xterm.h" /* for all of the X includes */ #include "dispextern.h" /* frame.h seems to want this */ @@ -30,6 +31,9 @@ Boston, MA 02111-1307, USA. */ #include "blockinput.h" #include "buffer.h" #include "process.h" +#include "termhooks.h" + +#include <X11/Xproto.h> struct prop_location; @@ -50,7 +54,9 @@ static struct prop_location *expect_property_change P_ ((Display *, Window, static void unexpect_property_change P_ ((struct prop_location *)); static Lisp_Object wait_for_property_change_unwind P_ ((Lisp_Object)); static void wait_for_property_change P_ ((struct prop_location *)); -static Lisp_Object x_get_foreign_selection P_ ((Lisp_Object, Lisp_Object)); +static Lisp_Object x_get_foreign_selection P_ ((Lisp_Object, + Lisp_Object, + Lisp_Object)); static void x_get_window_property P_ ((Display *, Window, Atom, unsigned char **, int *, Atom *, int *, unsigned long *, int)); @@ -1215,8 +1221,8 @@ static Window reading_selection_window; Converts this to Lisp data and returns it. */ static Lisp_Object -x_get_foreign_selection (selection_symbol, target_type) - Lisp_Object selection_symbol, target_type; +x_get_foreign_selection (selection_symbol, target_type, time_stamp) + Lisp_Object selection_symbol, target_type, time_stamp; { struct frame *sf = SELECTED_FRAME (); Window requestor_window = FRAME_X_WINDOW (sf); @@ -1235,6 +1241,18 @@ x_get_foreign_selection (selection_symbol, target_type) else type_atom = symbol_to_x_atom (dpyinfo, display, target_type); + if (! NILP (time_stamp)) + { + if (CONSP (time_stamp)) + requestor_time = (Time) cons_to_long (time_stamp); + else if (INTEGERP (time_stamp)) + requestor_time = (Time) XUINT (time_stamp); + else if (FLOATP (time_stamp)) + requestor_time = (Time) XFLOAT (time_stamp); + else + error ("TIME_STAMP must be cons or number"); + } + BLOCK_INPUT; count = x_catch_errors (display); @@ -1926,13 +1944,15 @@ anything that the functions on `selection-converter-alist' know about. */) will block until all of the data has arrived. */ DEFUN ("x-get-selection-internal", Fx_get_selection_internal, - Sx_get_selection_internal, 2, 2, 0, + Sx_get_selection_internal, 2, 3, 0, doc: /* Return text selected from some X window. SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'. \(Those are literal upper-case symbol names, since that's what X expects.) -TYPE is the type of data desired, typically `STRING'. */) - (selection_symbol, target_type) - Lisp_Object selection_symbol, target_type; +TYPE is the type of data desired, typically `STRING'. +TIME_STAMP is the time to use in the XConvertSelection call for foreign +selections. If omitted, defaults to the time for the last event. */) + (selection_symbol, target_type, time_stamp) + Lisp_Object selection_symbol, target_type, time_stamp; { Lisp_Object val = Qnil; struct gcpro gcpro1, gcpro2; @@ -1956,7 +1976,7 @@ TYPE is the type of data desired, typically `STRING'. */) if (NILP (val)) { - val = x_get_foreign_selection (selection_symbol, target_type); + val = x_get_foreign_selection (selection_symbol, target_type, time_stamp); goto DONE; } @@ -2278,6 +2298,351 @@ Positive means shift the values forward, negative means backward. */) #endif +/*********************************************************************** + Drag and drop support +***********************************************************************/ +/* Check that lisp values are of correct type for x_fill_property_data. + That is, number, string or a cons with two numbers (low and high 16 + bit parts of a 32 bit number). */ + +int +x_check_property_data (data) + Lisp_Object data; +{ + Lisp_Object iter; + int size = 0; + + for (iter = data; CONSP (iter) && size != -1; iter = XCDR (iter), ++size) + { + Lisp_Object o = XCAR (iter); + + if (! NUMBERP (o) && ! STRINGP (o) && ! CONSP (o)) + size = -1; + else if (CONSP (o) && + (! NUMBERP (XCAR (o)) || ! NUMBERP (XCDR (o)))) + size = -1; + } + + return size; +} + +/* Convert lisp values to a C array. Values may be a number, a string + which is taken as an X atom name and converted to the atom value, or + a cons containing the two 16 bit parts of a 32 bit number. + + DPY is the display use to look up X atoms. + DATA is a Lisp list of values to be converted. + RET is the C array that contains the converted values. It is assumed + it is big enough to hol all values. + FORMAT is 8, 16 or 32 and gives the size in bits for each C value to + be stored in RET. */ + +void +x_fill_property_data (dpy, data, ret, format) + Display *dpy; + Lisp_Object data; + void *ret; + int format; +{ + CARD32 val; + CARD32 *d32 = (CARD32 *) ret; + CARD16 *d16 = (CARD16 *) ret; + CARD8 *d08 = (CARD8 *) ret; + Lisp_Object iter; + + for (iter = data; CONSP (iter); iter = XCDR (iter)) + { + Lisp_Object o = XCAR (iter); + + if (INTEGERP (o)) + val = (CARD32) XFASTINT (o); + else if (FLOATP (o)) + val = (CARD32) XFLOAT (o); + else if (CONSP (o)) + val = (CARD32) cons_to_long (o); + else if (STRINGP (o)) + { + BLOCK_INPUT; + val = XInternAtom (dpy, (char *) SDATA (o), False); + UNBLOCK_INPUT; + } + else + error ("Wrong type, must be string, number or cons"); + + if (format == 8) + *d08++ = (CARD8) val; + else if (format == 16) + *d16++ = (CARD16) val; + else + *d32++ = val; + } +} + +/* Convert an array of C values to a Lisp list. + F is the frame to be used to look up X atoms if the TYPE is XA_ATOM. + DATA is a C array of values to be converted. + TYPE is the type of the data. Only XA_ATOM is special, it converts + each number in DATA to its corresponfing X atom as a symbol. + FORMAT is 8, 16 or 32 and gives the size in bits for each C value to + be stored in RET. + SIZE is the number of elements in DATA. + + Also see comment for selection_data_to_lisp_data above. */ + +Lisp_Object +x_property_data_to_lisp (f, data, type, format, size) + struct frame *f; + unsigned char *data; + Atom type; + int format; + unsigned long size; +{ + return selection_data_to_lisp_data (FRAME_X_DISPLAY (f), + data, size*format/8, type, format); +} + +/* Get the mouse position frame relative coordinates. */ + +static void +mouse_position_for_drop (f, x, y) + FRAME_PTR f; + int *x; + int *y; +{ + Window root, dummy_window; + int dummy; + + BLOCK_INPUT; + + XQueryPointer (FRAME_X_DISPLAY (f), + DefaultRootWindow (FRAME_X_DISPLAY (f)), + + /* The root window which contains the pointer. */ + &root, + + /* Window pointer is on, not used */ + &dummy_window, + + /* The position on that root window. */ + x, y, + + /* x/y in dummy_window coordinates, not used. */ + &dummy, &dummy, + + /* Modifier keys and pointer buttons, about which + we don't care. */ + (unsigned int *) &dummy); + + + /* Absolute to relative. */ + *x -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); + *y -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); + + UNBLOCK_INPUT; +} + +DEFUN ("x-get-atom-name", Fx_get_atom_name, + Sx_get_atom_name, 1, 2, 0, + doc: /* Return the X atom name for VALUE as a string. +VALUE may be a number or a cons where the car is the upper 16 bits and +the cdr is the lower 16 bits of a 32 bit value. +Use the display for FRAME or the current frame if FRAME is not given or nil. + +If the value is 0 or the atom is not known, return the empty string. */) + (value, frame) + Lisp_Object value, frame; +{ + struct frame *f = check_x_frame (frame); + char *name = 0; + Lisp_Object ret = Qnil; + int count; + Display *dpy = FRAME_X_DISPLAY (f); + Atom atom; + + if (INTEGERP (value)) + atom = (Atom) XUINT (value); + else if (FLOATP (value)) + atom = (Atom) XFLOAT (value); + else if (CONSP (value)) + atom = (Atom) cons_to_long (value); + else + error ("Wrong type, value must be number or cons"); + + BLOCK_INPUT; + count = x_catch_errors (dpy); + + name = atom ? XGetAtomName (dpy, atom) : ""; + + if (! x_had_errors_p (dpy)) + ret = make_string (name, strlen (name)); + + x_uncatch_errors (dpy, count); + + if (atom && name) XFree (name); + if (NILP (ret)) ret = make_string ("", 0); + + UNBLOCK_INPUT; + + return ret; +} + +/* Convert an XClientMessageEvent to a Lisp event of type DRAG_N_DROP_EVENT. + TODO: Check if this client event really is a DND event? */ + +int +x_handle_dnd_message (f, event, dpyinfo, bufp) + struct frame *f; + XClientMessageEvent *event; + struct x_display_info *dpyinfo; + struct input_event *bufp; +{ + Lisp_Object vec; + Lisp_Object frame; + unsigned long size = (8*sizeof (event->data))/event->format; + int x, y; + + XSETFRAME (frame, f); + + vec = Fmake_vector (make_number (4), Qnil); + AREF (vec, 0) = SYMBOL_NAME (x_atom_to_symbol (FRAME_X_DISPLAY (f), + event->message_type)); + AREF (vec, 1) = frame; + AREF (vec, 2) = make_number (event->format); + AREF (vec, 3) = x_property_data_to_lisp (f, + event->data.b, + event->message_type, + event->format, + size); + + mouse_position_for_drop (f, &x, &y); + bufp->kind = DRAG_N_DROP_EVENT; + bufp->frame_or_window = Fcons (frame, vec); + bufp->timestamp = CurrentTime; + bufp->x = make_number (x); + bufp->y = make_number (y); + bufp->arg = Qnil; + bufp->modifiers = 0; + + return 1; +} + +DEFUN ("x-send-client-message", Fx_send_client_event, + Sx_send_client_message, 6, 6, 0, + doc: /* Send a client message of MESSAGE-TYPE to window DEST on DISPLAY. + +For DISPLAY, specify either a frame or a display name (a string). +If DISPLAY is nil, that stands for the selected frame's display. +DEST may be a number, in which case it is a Window id. The value 0 may +be used to send to the root window of the DISPLAY. +If DEST is a cons, it is converted to a 32 bit number +with the high 16 bits from the car and the lower 16 bit from the cdr. That +number is then used as a window id. +If DEST is a frame the event is sent to the outer window of that frame. +Nil means the currently selected frame. +If DEST is the string "PointerWindow" the event is sent to the window that +contains the pointer. If DEST is the string "InputFocus" the event is +sent to the window that has the input focus. +FROM is the frame sending the event. Use nil for currently selected frame. +MESSAGE-TYPE is the name of an Atom as a string. +FORMAT must be one of 8, 16 or 32 and determines the size of the values in +bits. VALUES is a list of numbers, cons and/or strings containing the values +to send. If a value is a string, it is converted to an Atom and the value of +the Atom is sent. If a value is a cons, it is converted to a 32 bit number +with the high 16 bits from the car and the lower 16 bit from the cdr. +If more values than fits into the event is given, the excessive values +are ignored. */) + (display, dest, from, message_type, format, values) + Lisp_Object display, dest, from, message_type, format, values; +{ + struct x_display_info *dpyinfo = check_x_display_info (display); + Window wdest; + XEvent event; + Lisp_Object cons; + int size; + struct frame *f = check_x_frame (from); + int count; + int to_root; + + CHECK_STRING (message_type); + CHECK_NUMBER (format); + CHECK_CONS (values); + + if (x_check_property_data (values) == -1) + error ("Bad data in VALUES, must be number, cons or string"); + + event.xclient.type = ClientMessage; + event.xclient.format = XFASTINT (format); + + if (event.xclient.format != 8 && event.xclient.format != 16 + && event.xclient.format != 32) + error ("FORMAT must be one of 8, 16 or 32"); + + if (FRAMEP (dest) || NILP (dest)) + { + struct frame *fdest = check_x_frame (dest); + wdest = FRAME_OUTER_WINDOW (fdest); + } + else if (STRINGP (dest)) + { + if (strcmp (SDATA (dest), "PointerWindow") == 0) + wdest = PointerWindow; + else if (strcmp (SDATA (dest), "InputFocus") == 0) + wdest = InputFocus; + else + error ("DEST as a string must be one of PointerWindow or InputFocus"); + } + else if (INTEGERP (dest)) + wdest = (Window) XFASTINT (dest); + else if (FLOATP (dest)) + wdest = (Window) XFLOAT (dest); + else if (CONSP (dest)) + { + if (! NUMBERP (XCAR (dest)) || ! NUMBERP (XCDR (dest))) + error ("Both car and cdr for DEST must be numbers"); + else + wdest = (Window) cons_to_long (dest); + } + else + error ("DEST must be a frame, nil, string, number or cons"); + + if (wdest == 0) wdest = dpyinfo->root_window; + to_root = wdest == dpyinfo->root_window; + + for (cons = values, size = 0; CONSP (cons); cons = XCDR (cons), ++size) + ; + + BLOCK_INPUT; + + event.xclient.message_type + = XInternAtom (dpyinfo->display, SDATA (message_type), False); + event.xclient.display = dpyinfo->display; + + /* Some clients (metacity for example) expects sending window to be here + when sending to the root window. */ + event.xclient.window = to_root ? FRAME_OUTER_WINDOW (f) : wdest; + + memset (event.xclient.data.b, 0, sizeof (event.xclient.data.b)); + x_fill_property_data (dpyinfo->display, values, event.xclient.data.b, + event.xclient.format); + + /* If event mask is 0 the event is sent to the client that created + the destination window. But if we are sending to the root window, + there is no such client. Then we set the event mask to 0xffff. The + event then goes to clients selecting for events on the root window. */ + count = x_catch_errors (dpyinfo->display); + { + int propagate = to_root ? False : True; + unsigned mask = to_root ? 0xffff : 0; + XSendEvent (dpyinfo->display, wdest, propagate, mask, &event); + XFlush (dpyinfo->display); + } + x_uncatch_errors (dpyinfo->display, count); + UNBLOCK_INPUT; + + return Qnil; +} + + void syms_of_xselect () { @@ -2293,6 +2658,9 @@ syms_of_xselect () defsubr (&Sx_rotate_cut_buffers_internal); #endif + defsubr (&Sx_get_atom_name); + defsubr (&Sx_send_client_message); + reading_selection_reply = Fcons (Qnil, Qnil); staticpro (&reading_selection_reply); reading_selection_window = 0; @@ -2400,3 +2768,6 @@ A value of 0 means wait as long as necessary. This is initialized from the Qforeign_selection = intern ("foreign-selection"); staticpro (&Qforeign_selection); } + +/* arch-tag: 7c293b0f-9918-4f69-8ac7-03e142307236 + (do not change this comment) */ diff --git a/src/xsmfns.c b/src/xsmfns.c index 5e712fa1b38..e486e5c6e32 100644 --- a/src/xsmfns.c +++ b/src/xsmfns.c @@ -24,6 +24,9 @@ Boston, MA 02111-1307, USA. */ #ifdef HAVE_X_SM #include <X11/SM/SMlib.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> + #ifdef HAVE_STRING_H #include <string.h> #else @@ -47,6 +50,7 @@ Boston, MA 02111-1307, USA. */ #include "lisp.h" #include "termhooks.h" #include "termopts.h" +#include "xterm.h" #ifndef MAXPATHLEN #define MAXPATHLEN 1024 @@ -102,13 +106,10 @@ Lisp_Object Vx_session_previous_id; /* Handle any messages from the session manager. If no connection is open to a session manager, just return 0. - Otherwise returns the number of events stored in buffer BUFP, - which can hold up to *NUMCHARS characters. At most one event is - stored, a SAVE_SESSION_EVENT. */ + Otherwise returns 1 if SAVE_SESSION_EVENT is stored in buffer BUFP. */ int -x_session_check_input (bufp, numchars) +x_session_check_input (bufp) struct input_event *bufp; - int *numchars; { SELECT_TYPE read_fds; EMACS_TIME tmout; @@ -142,16 +143,11 @@ x_session_check_input (bufp, numchars) /* Check if smc_interact_CB was called and we shall generate a SAVE_SESSION_EVENT. */ - if (*numchars > 0 && emacs_event.kind != NO_EVENT) - { - bcopy (&emacs_event, bufp, sizeof (struct input_event)); - bufp++; - (*numchars)--; + if (emacs_event.kind == NO_EVENT) + return 0; - return 1; - } - - return 0; + bcopy (&emacs_event, bufp, sizeof (struct input_event)); + return 1; } /* Return non-zero if we have a connection to a session manager.*/ @@ -403,9 +399,37 @@ ice_conn_watch_CB (iceConn, clientData, opening, watchData) #endif /* ! defined (SIGIO) */ } +/* Create the client leader window. */ +static void +create_client_leader_window (dpyinfo, client_id) + struct x_display_info *dpyinfo; + char *client_id; +{ + Window w; + XClassHint class_hints; + Atom sm_id; + + w = XCreateSimpleWindow (dpyinfo->display, + dpyinfo->root_window, + -1, -1, 1, 1, + CopyFromParent, CopyFromParent, CopyFromParent); + + class_hints.res_name = (char *) SDATA (Vx_resource_name); + class_hints.res_class = (char *) SDATA (Vx_resource_class); + XSetClassHint (dpyinfo->display, w, &class_hints); + XStoreName (dpyinfo->display, w, class_hints.res_name); + + sm_id = XInternAtom (dpyinfo->display, "SM_CLIENT_ID", False); + XChangeProperty (dpyinfo->display, w, sm_id, XA_STRING, 8, PropModeReplace, + client_id, strlen (client_id)); + + dpyinfo->client_leader_window = w; +} + /* Try to open a connection to the session manager. */ void -x_session_initialize () +x_session_initialize (dpyinfo) + struct x_display_info *dpyinfo; { #define SM_ERRORSTRING_LEN 512 char errorstring[SM_ERRORSTRING_LEN]; @@ -466,7 +490,17 @@ x_session_initialize () errorstring); if (smc_conn != 0) - Vx_session_id = make_string (client_id, strlen (client_id)); + { + Vx_session_id = make_string (client_id, strlen (client_id)); + +#ifdef USE_GTK + /* GTK creats a leader window by itself, but we need to tell + it about our client_id. */ + gdk_set_sm_client_id (client_id); +#else + create_client_leader_window (dpyinfo, client_id); +#endif + } } @@ -544,3 +578,6 @@ See also `emacs-save-session-functions', `emacs-session-save' and } #endif /* HAVE_X_SM */ + +/* arch-tag: 56a2c58c-adfa-430a-b772-130abd29fd2e + (do not change this comment) */ diff --git a/src/xterm.c b/src/xterm.c index 82aed60fbd6..ae4d4063be9 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -132,6 +132,7 @@ extern void _XEditResCheckMessages (); #include <X11/Xaw3d/Simple.h> #include <X11/Xaw3d/Scrollbar.h> #define ARROW_SCROLLBAR +#define XAW_ARROW_SCROLLBARS #include <X11/Xaw3d/ScrollbarP.h> #else /* !HAVE_XAW3D */ #include <X11/Xaw/Simple.h> @@ -217,6 +218,17 @@ static String Xt_default_resources[] = {0}; static int toolkit_scroll_bar_interaction; +/* Non-zero means to not move point as a result of clicking on a + frame to focus it (when focus-follows-mouse is nil). */ + +int x_mouse_click_focus_ignore_position; + +/* Non-zero timeout value means ignore next mouse click if it arrives + before that timeout elapses (i.e. as part of the same sequence of + events resulting from clicking on a frame to select it). */ + +static unsigned long ignore_next_mouse_click_timeout; + /* Mouse movement. Formerly, we used PointerMotionHintMask (in standard_event_mask) @@ -287,7 +299,7 @@ extern Lisp_Object Vcommand_line_args, Vsystem_name; extern Lisp_Object Vx_no_window_manager; -extern Lisp_Object Qface, Qmouse_face, Qeql; +extern Lisp_Object Qeql; extern int errno; @@ -336,16 +348,10 @@ static void x_clear_frame P_ ((void)); static void frame_highlight P_ ((struct frame *)); static void frame_unhighlight P_ ((struct frame *)); static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *)); -static int x_focus_changed P_ ((int, - int, - struct x_display_info *, - struct frame *, - struct input_event *, - int)); -static int x_detect_focus_change P_ ((struct x_display_info *, - XEvent *, - struct input_event *, - int)); +static void x_focus_changed P_ ((int, int, struct x_display_info *, + struct frame *, struct input_event *)); +static void x_detect_focus_change P_ ((struct x_display_info *, + XEvent *, struct input_event *)); static void XTframe_rehighlight P_ ((struct frame *)); static void x_frame_rehighlight P_ ((struct x_display_info *)); static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *)); @@ -357,18 +363,15 @@ static void x_flush P_ ((struct frame *f)); static void x_update_begin P_ ((struct frame *)); static void x_update_window_begin P_ ((struct window *)); static void x_after_update_window_line P_ ((struct glyph_row *)); -static struct scroll_bar *x_window_to_scroll_bar P_ ((Window)); +static struct scroll_bar *x_window_to_scroll_bar P_ ((Display *, Window)); static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *, enum scroll_bar_part *, Lisp_Object *, Lisp_Object *, unsigned long *)); static void x_check_fullscreen P_ ((struct frame *)); -static void x_check_fullscreen_move P_ ((struct frame *)); -static int handle_one_xevent P_ ((struct x_display_info *, - XEvent *, - struct input_event **, - int *, - int *)); +static void x_check_expected_move P_ ((struct frame *)); +static int handle_one_xevent P_ ((struct x_display_info *, XEvent *, + int *, struct input_event *)); /* Flush display of frame F, or of all frames if F is null. */ @@ -570,6 +573,9 @@ x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p) output_cursor.x, output_cursor.y); x_draw_vertical_border (w); + + draw_window_fringes (w); + UNBLOCK_INPUT; } @@ -649,11 +655,7 @@ x_after_update_window_line (desired_row) xassert (w); if (!desired_row->mode_line_p && !w->pseudo_window_p) - { - BLOCK_INPUT; - draw_row_fringe_bitmaps (w, desired_row); - UNBLOCK_INPUT; - } + desired_row->redraw_fringe_bitmaps_p = 1; /* When a window has disappeared, make sure that no rest of full-width rows stays visible in the internal border. Could @@ -697,11 +699,26 @@ x_draw_fringe_bitmap (w, row, p) Window window = FRAME_X_WINDOW (f); GC gc = f->output_data.x->normal_gc; struct face *face = p->face; + int rowY; /* Must clip because of partially visible lines. */ - x_clip_to_row (w, row, gc); + rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); + if (p->y < rowY) + { + /* Adjust position of "bottom aligned" bitmap on partially + visible last row. */ + int oldY = row->y; + int oldVH = row->visible_height; + row->visible_height = p->h; + row->y -= rowY - p->y; + x_clip_to_row (w, row, gc); + row->y = oldY; + row->visible_height = oldVH; + } + else + x_clip_to_row (w, row, gc); - if (p->bx >= 0) + if (p->bx >= 0 && !p->overlay_p) { /* In case the same realized face is used for fringes and for something displayed in the text (e.g. face `region' on @@ -719,20 +736,49 @@ x_draw_fringe_bitmap (w, row, p) XSetForeground (display, face->gc, face->foreground); } - if (p->which != NO_FRINGE_BITMAP) + if (p->which) { - unsigned char *bits = fringe_bitmaps[p->which].bits + p->dh; - Pixmap pixmap; + unsigned char *bits; + Pixmap pixmap, clipmask = (Pixmap) 0; int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f)); + XGCValues gcv; + + if (p->wd > 8) + bits = (unsigned char *)(p->bits + p->dh); + else + bits = (unsigned char *)p->bits + p->dh; /* Draw the bitmap. I believe these small pixmaps can be cached by the server. */ pixmap = XCreatePixmapFromBitmapData (display, window, bits, p->wd, p->h, - face->foreground, + (p->cursor_p + ? (p->overlay_p ? face->background + : f->output_data.x->cursor_pixel) + : face->foreground), face->background, depth); + + if (p->overlay_p) + { + clipmask = XCreatePixmapFromBitmapData (display, + FRAME_X_DISPLAY_INFO (f)->root_window, + bits, p->wd, p->h, + 1, 0, 1); + gcv.clip_mask = clipmask; + gcv.clip_x_origin = p->x; + gcv.clip_y_origin = p->y; + XChangeGC (display, gc, GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv); + } + XCopyArea (display, pixmap, window, gc, 0, 0, p->wd, p->h, p->x, p->y); XFreePixmap (display, pixmap); + + if (p->overlay_p) + { + gcv.clip_mask = (Pixmap) 0; + XChangeGC (display, gc, GCClipMask, &gcv); + XFreePixmap (display, clipmask); + } } XSetClipMask (display, gc, None); @@ -3129,20 +3175,16 @@ x_new_focus_frame (dpyinfo, frame) /* Handle FocusIn and FocusOut state changes for FRAME. If FRAME has focus and there exists more than one frame, puts - a FOCUS_IN_EVENT into BUFP. - Returns number of events inserted into BUFP. */ + a FOCUS_IN_EVENT into *BUFP. */ -static int -x_focus_changed (type, state, dpyinfo, frame, bufp, numchars) +static void +x_focus_changed (type, state, dpyinfo, frame, bufp) int type; int state; struct x_display_info *dpyinfo; struct frame *frame; struct input_event *bufp; - int numchars; { - int nr_events = 0; - if (type == FocusIn) { if (dpyinfo->x_focus_event_frame != frame) @@ -3152,17 +3194,12 @@ x_focus_changed (type, state, dpyinfo, frame, bufp, numchars) /* Don't stop displaying the initial startup message for a switch-frame event we don't need. */ - if (numchars > 0 - && GC_NILP (Vterminal_frame) + if (GC_NILP (Vterminal_frame) && GC_CONSP (Vframe_list) && !GC_NILP (XCDR (Vframe_list))) { bufp->kind = FOCUS_IN_EVENT; XSETFRAME (bufp->frame_or_window, frame); - bufp->arg = Qnil; - ++bufp; - numchars--; - ++nr_events; } } @@ -3188,57 +3225,52 @@ x_focus_changed (type, state, dpyinfo, frame, bufp, numchars) XUnsetICFocus (FRAME_XIC (frame)); #endif } - - return nr_events; } /* The focus may have changed. Figure out if it is a real focus change, by checking both FocusIn/Out and Enter/LeaveNotify events. - Returns number of events inserted into BUFP. */ + Returns FOCUS_IN_EVENT event in *BUFP. */ -static int -x_detect_focus_change (dpyinfo, event, bufp, numchars) +static void +x_detect_focus_change (dpyinfo, event, bufp) struct x_display_info *dpyinfo; XEvent *event; struct input_event *bufp; - int numchars; { struct frame *frame; int nr_events = 0; frame = x_any_window_to_frame (dpyinfo, event->xany.window); - if (! frame) return nr_events; + if (! frame) + return; switch (event->type) { case EnterNotify: case LeaveNotify: - if (event->xcrossing.detail != NotifyInferior - && event->xcrossing.focus - && ! (frame->output_data.x->focus_state & FOCUS_EXPLICIT)) - nr_events = x_focus_changed ((event->type == EnterNotify - ? FocusIn : FocusOut), - FOCUS_IMPLICIT, - dpyinfo, - frame, - bufp, - numchars); + { + struct frame *focus_frame = dpyinfo->x_focus_event_frame; + int focus_state + = focus_frame ? focus_frame->output_data.x->focus_state : 0; + + if (event->xcrossing.detail != NotifyInferior + && event->xcrossing.focus + && ! (focus_state & FOCUS_EXPLICIT)) + x_focus_changed ((event->type == EnterNotify ? FocusIn : FocusOut), + FOCUS_IMPLICIT, + dpyinfo, frame, bufp); + } break; case FocusIn: case FocusOut: - nr_events = x_focus_changed (event->type, - (event->xfocus.detail == NotifyPointer - ? FOCUS_IMPLICIT : FOCUS_EXPLICIT), - dpyinfo, - frame, - bufp, - numchars); + x_focus_changed (event->type, + (event->xfocus.detail == NotifyPointer ? + FOCUS_IMPLICIT : FOCUS_EXPLICIT), + dpyinfo, frame, bufp); break; } - - return nr_events; } @@ -3583,35 +3615,39 @@ glyph_rect (f, x, y, rect) XRectangle *rect; { Lisp_Object window; - int found = 0; + struct window *w; + struct glyph_row *r, *end_row; window = window_from_coordinates (f, x, y, 0, &x, &y, 0); - if (!NILP (window)) - { - struct window *w = XWINDOW (window); - struct glyph_row *r = MATRIX_FIRST_TEXT_ROW (w->current_matrix); - struct glyph_row *end = r + w->current_matrix->nrows - 1; + if (NILP (window)) + return 0; - for (; !found && r < end && r->enabled_p; ++r) - if (r->y >= y) - { - struct glyph *g = r->glyphs[TEXT_AREA]; - struct glyph *end = g + r->used[TEXT_AREA]; - int gx; + w = XWINDOW (window); + r = MATRIX_FIRST_TEXT_ROW (w->current_matrix); + end_row = r + w->current_matrix->nrows - 1; - for (gx = r->x; !found && g < end; gx += g->pixel_width, ++g) - if (gx >= x) - { - rect->width = g->pixel_width; - rect->height = r->height; - rect->x = WINDOW_TO_FRAME_PIXEL_X (w, gx); - rect->y = WINDOW_TO_FRAME_PIXEL_Y (w, r->y); - found = 1; - } - } + for (; r < end_row && r->enabled_p; ++r) + { + if (r->y >= y) + { + struct glyph *g = r->glyphs[TEXT_AREA]; + struct glyph *end = g + r->used[TEXT_AREA]; + int gx = r->x; + while (g < end && gx < x) + gx += g->pixel_width, ++g; + if (g < end) + { + rect->width = g->pixel_width; + rect->height = r->height; + rect->x = WINDOW_TO_FRAME_PIXEL_X (w, gx); + rect->y = WINDOW_TO_FRAME_PIXEL_Y (w, r->y); + return 1; + } + break; + } } - return found; + return 0; } @@ -3776,7 +3812,9 @@ XTmouse_position (fp, insist, bar_window, part, x, y, time) /* If not, is it one of our scroll bars? */ if (! f1) { - struct scroll_bar *bar = x_window_to_scroll_bar (win); + struct scroll_bar *bar; + + bar = x_window_to_scroll_bar (FRAME_X_DISPLAY (*fp), win); if (bar) { @@ -3847,18 +3885,20 @@ XTmouse_position (fp, insist, bar_window, part, x, y, time) /* Scroll bar support. */ -/* Given an X window ID, find the struct scroll_bar which manages it. +/* Given an X window ID and a DISPLAY, find the struct scroll_bar which + manages it. This can be called in GC, so we have to make sure to strip off mark bits. */ static struct scroll_bar * -x_window_to_scroll_bar (window_id) +x_window_to_scroll_bar (display, window_id) + Display *display; Window window_id; { Lisp_Object tail; #ifdef USE_GTK - window_id = (Window) xg_get_scroll_id_for_window (window_id); + window_id = (Window) xg_get_scroll_id_for_window (display, window_id); #endif /* USE_GTK */ for (tail = Vframe_list; @@ -3882,7 +3922,8 @@ x_window_to_scroll_bar (window_id) condemned = Qnil, ! GC_NILP (bar)); bar = XSCROLL_BAR (bar)->next) - if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id) + if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id && + FRAME_X_DISPLAY (XFRAME (frame)) == display) return XSCROLL_BAR (bar); } @@ -5599,6 +5640,11 @@ static XComposeStatus compose_status; static int temp_index; static short temp_buffer[100]; +#define STORE_KEYSYM_FOR_DEBUG(keysym) \ + if (temp_index == sizeof temp_buffer / sizeof (short)) \ + temp_index = 0; \ + temp_buffer[temp_index++] = (keysym) + /* Set this to nonzero to fake an "X I/O error" on a particular display. */ @@ -5618,15 +5664,8 @@ static struct x_display_info *next_noop_dpyinfo; f->output_data.x->saved_menu_event \ = (XEvent *) xmalloc (sizeof (XEvent)); \ bcopy (&event, f->output_data.x->saved_menu_event, size); \ - if (numchars >= 1) \ - { \ - bufp->kind = MENU_BAR_ACTIVATE_EVENT; \ - XSETFRAME (bufp->frame_or_window, f); \ - bufp->arg = Qnil; \ - bufp++; \ - count++; \ - numchars--; \ - } \ + inev.kind = MENU_BAR_ACTIVATE_EVENT; \ + XSETFRAME (inev.frame_or_window, f); \ } \ while (0) @@ -5668,41 +5707,47 @@ x_filter_event (dpyinfo, event) #endif #ifdef USE_GTK -static struct x_display_info *current_dpyinfo; -static struct input_event **current_bufp; -static int *current_numcharsp; static int current_count; static int current_finish; +static struct input_event *current_hold_quit; /* This is the filter function invoked by the GTK event loop. It is invoked before the XEvent is translated to a GdkEvent, - so we have a chanse to act on the event before GTK. */ + so we have a chance to act on the event before GTK. */ static GdkFilterReturn event_handler_gdk (gxev, ev, data) GdkXEvent *gxev; GdkEvent *ev; gpointer data; { - XEvent *xev = (XEvent*)gxev; + XEvent *xev = (XEvent *) gxev; - if (current_numcharsp) + if (current_count >= 0) { + struct x_display_info *dpyinfo; + + dpyinfo = x_display_info_for_display (xev->xany.display); + #ifdef HAVE_X_I18N /* Filter events for the current X input method. GTK calls XFilterEvent but not for key press and release, so we do it here. */ if (xev->type == KeyPress || xev->type == KeyRelease) - if (x_filter_event (current_dpyinfo, xev)) + if (dpyinfo && x_filter_event (dpyinfo, xev)) return GDK_FILTER_REMOVE; #endif - current_count += handle_one_xevent (current_dpyinfo, - xev, - current_bufp, - current_numcharsp, - ¤t_finish); + + if (! dpyinfo) + current_finish = X_EVENT_NORMAL; + else + { + current_count += + handle_one_xevent (dpyinfo, xev, ¤t_finish, + current_hold_quit); + } } else - current_finish = x_dispatch_event (xev, GDK_DISPLAY ()); + current_finish = x_dispatch_event (xev, xev->xany.display); if (current_finish == X_EVENT_GOTO_OUT || current_finish == X_EVENT_DROP) return GDK_FILTER_REMOVE; @@ -5718,28 +5763,29 @@ event_handler_gdk (gxev, ev, data) *FINISH is zero if caller should continue reading events. *FINISH is X_EVENT_DROP if event should not be passed to the toolkit. - Events representing keys are stored in buffer *BUFP_R, - which can hold up to *NUMCHARSP characters. We return the number of characters stored into the buffer. */ static int -handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) +handle_one_xevent (dpyinfo, eventp, finish, hold_quit) struct x_display_info *dpyinfo; XEvent *eventp; - /* register */ struct input_event **bufp_r; - /* register */ int *numcharsp; int *finish; + struct input_event *hold_quit; { + struct input_event inev; int count = 0; + int do_help = 0; int nbytes = 0; struct frame *f; struct coding_system coding; - struct input_event *bufp = *bufp_r; - int numchars = *numcharsp; XEvent event = *eventp; *finish = X_EVENT_NORMAL; + EVENT_INIT (inev); + inev.kind = NO_EVENT; + inev.arg = Qnil; + switch (event.type) { case ClientMessage: @@ -5794,8 +5840,10 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) } /* Not certain about handling scroll bars here */ #endif /* 0 */ + goto done; } - else if (event.xclient.data.l[0] + + if (event.xclient.data.l[0] == dpyinfo->Xatom_wm_save_yourself) { /* Save state modify the WM_COMMAND property to @@ -5806,11 +5854,9 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) /* If we have a session manager, don't set this. KDE will then start two Emacsen, one for the session manager and one for this. */ - if (numchars > 0 #ifdef HAVE_X_SM - && ! x_session_have_connection () + if (! x_session_have_connection ()) #endif - ) { f = x_top_window_to_frame (dpyinfo, event.xclient.window); @@ -5825,41 +5871,36 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) event.xclient.window, 0, 0); } + goto done; } - else if (event.xclient.data.l[0] - == dpyinfo->Xatom_wm_delete_window) + + if (event.xclient.data.l[0] + == dpyinfo->Xatom_wm_delete_window) { - struct frame *f - = x_any_window_to_frame (dpyinfo, + f = x_any_window_to_frame (dpyinfo, event.xclient.window); + if (!f) + goto OTHER; /* May be a dialog that is to be removed */ - if (f) - { - if (numchars == 0) - abort (); - - bufp->kind = DELETE_WINDOW_EVENT; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp++; - - count += 1; - numchars -= 1; - } - else - goto OTHER; /* May be a dialog that is to be removed */ + inev.kind = DELETE_WINDOW_EVENT; + XSETFRAME (inev.frame_or_window, f); + goto done; } + + goto done; } - else if (event.xclient.message_type + + if (event.xclient.message_type == dpyinfo->Xatom_wm_configure_denied) { + goto done; } - else if (event.xclient.message_type - == dpyinfo->Xatom_wm_window_moved) + + if (event.xclient.message_type + == dpyinfo->Xatom_wm_window_moved) { int new_x, new_y; - struct frame *f - = x_window_to_frame (dpyinfo, event.xclient.window); + f = x_window_to_frame (dpyinfo, event.xclient.window); new_x = event.xclient.data.s[0]; new_y = event.xclient.data.s[1]; @@ -5869,45 +5910,55 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) f->left_pos = new_x; f->top_pos = new_y; } + goto done; } + #ifdef HACK_EDITRES - else if (event.xclient.message_type - == dpyinfo->Xatom_editres) + if (event.xclient.message_type + == dpyinfo->Xatom_editres) { - struct frame *f - = x_any_window_to_frame (dpyinfo, event.xclient.window); + f = x_any_window_to_frame (dpyinfo, event.xclient.window); _XEditResCheckMessages (f->output_data.x->widget, NULL, &event, NULL); + goto done; } #endif /* HACK_EDITRES */ - else if ((event.xclient.message_type - == dpyinfo->Xatom_DONE) - || (event.xclient.message_type - == dpyinfo->Xatom_PAGE)) + + if ((event.xclient.message_type + == dpyinfo->Xatom_DONE) + || (event.xclient.message_type + == dpyinfo->Xatom_PAGE)) { /* Ghostview job completed. Kill it. We could reply with "Next" if we received "Page", but we currently never do because we are interested in images, only, which should have 1 page. */ Pixmap pixmap = (Pixmap) event.xclient.data.l[1]; - struct frame *f - = x_window_to_frame (dpyinfo, event.xclient.window); + f = x_window_to_frame (dpyinfo, event.xclient.window); x_kill_gs_process (pixmap, f); expose_frame (f, 0, 0, 0, 0); + goto done; } + #ifdef USE_TOOLKIT_SCROLL_BARS /* Scroll bar callbacks send a ClientMessage from which we construct an input_event. */ - else if (event.xclient.message_type - == dpyinfo->Xatom_Scrollbar) + if (event.xclient.message_type + == dpyinfo->Xatom_Scrollbar) { - x_scroll_bar_to_input_event (&event, bufp); - ++bufp, ++count, --numchars; - goto out; + x_scroll_bar_to_input_event (&event, &inev); + *finish = X_EVENT_GOTO_OUT; + goto done; } #endif /* USE_TOOLKIT_SCROLL_BARS */ - else - goto OTHER; + + f = x_any_window_to_frame (dpyinfo, event.xclient.window); + + if (!f) + goto OTHER; + + if (x_handle_dnd_message (f, &event.xclient, dpyinfo, &inev)) + *finish = X_EVENT_DROP; } break; @@ -5927,19 +5978,11 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) { XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event; - if (numchars == 0) - abort (); - - bufp->kind = SELECTION_CLEAR_EVENT; - SELECTION_EVENT_DISPLAY (bufp) = eventp->display; - SELECTION_EVENT_SELECTION (bufp) = eventp->selection; - SELECTION_EVENT_TIME (bufp) = eventp->time; - bufp->frame_or_window = Qnil; - bufp->arg = Qnil; - bufp++; - - count += 1; - numchars -= 1; + inev.kind = SELECTION_CLEAR_EVENT; + SELECTION_EVENT_DISPLAY (&inev) = eventp->display; + SELECTION_EVENT_SELECTION (&inev) = eventp->selection; + SELECTION_EVENT_TIME (&inev) = eventp->time; + inev.frame_or_window = Qnil; } break; @@ -5956,22 +5999,14 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event; - if (numchars == 0) - abort (); - - bufp->kind = SELECTION_REQUEST_EVENT; - SELECTION_EVENT_DISPLAY (bufp) = eventp->display; - SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor; - SELECTION_EVENT_SELECTION (bufp) = eventp->selection; - SELECTION_EVENT_TARGET (bufp) = eventp->target; - SELECTION_EVENT_PROPERTY (bufp) = eventp->property; - SELECTION_EVENT_TIME (bufp) = eventp->time; - bufp->frame_or_window = Qnil; - bufp->arg = Qnil; - bufp++; - - count += 1; - numchars -= 1; + inev.kind = SELECTION_REQUEST_EVENT; + SELECTION_EVENT_DISPLAY (&inev) = eventp->display; + SELECTION_EVENT_REQUESTOR (&inev) = eventp->requestor; + SELECTION_EVENT_SELECTION (&inev) = eventp->selection; + SELECTION_EVENT_TARGET (&inev) = eventp->target; + SELECTION_EVENT_PROPERTY (&inev) = eventp->property; + SELECTION_EVENT_TIME (&inev) = eventp->time; + inev.frame_or_window = Qnil; } break; @@ -5996,9 +6031,11 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) x_real_positions (f, &x, &y); f->left_pos = x; f->top_pos = y; + + /* Perhaps reparented due to a WM restart. Reset this. */ + FRAME_X_DISPLAY_INFO (f)->wm_type = X_WMTYPE_UNKNOWN; } goto OTHER; - break; case Expose: f = x_window_to_frame (dpyinfo, event.xexpose.window); @@ -6039,7 +6076,8 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) /* Dispatch event to the widget. */ goto OTHER; #else /* not USE_TOOLKIT_SCROLL_BARS */ - bar = x_window_to_scroll_bar (event.xexpose.window); + bar = x_window_to_scroll_bar (event.xexpose.display, + event.xexpose.window); if (bar) x_scroll_bar_expose (bar, &event); @@ -6099,12 +6137,8 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) { f->async_iconified = 1; - bufp->kind = ICONIFY_EVENT; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp++; - count++; - numchars--; + inev.kind = ICONIFY_EVENT; + XSETFRAME (inev.frame_or_window, f); } } goto OTHER; @@ -6136,12 +6170,8 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) if (f->iconified) { - bufp->kind = DEICONIFY_EVENT; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp++; - count++; - numchars--; + inev.kind = DEICONIFY_EVENT; + XSETFRAME (inev.frame_or_window, f); } else if (! NILP (Vframe_list) && ! NILP (XCDR (Vframe_list))) @@ -6154,6 +6184,8 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) case KeyPress: + ignore_next_mouse_click_timeout = 0; + #if defined (USE_X_TOOLKIT) || defined (USE_GTK) /* Dispatch KeyPress events when in menu. */ if (popup_activated ()) @@ -6164,8 +6196,8 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)) { - dpyinfo->mouse_face_hidden = 1; clear_mouse_face (dpyinfo); + dpyinfo->mouse_face_hidden = 1; } #if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS @@ -6202,6 +6234,15 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) int copy_bufsiz = sizeof (copy_buffer); int modifiers; Lisp_Object coding_system = Qlatin_1; + Lisp_Object c; + +#ifdef USE_GTK + /* Don't pass keys to GTK. A Tab will shift focus to the + tool bar in GTK 2.4. Keys will still go to menus and + dialogs because in that case popup_activated is TRUE + (see above). */ + *finish = X_EVENT_DROP; +#endif event.xkey.state |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f), @@ -6288,51 +6329,44 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) &compose_status); #endif + /* If not using XIM/XIC, and a compose sequence is in progress, + we break here. Otherwise, chars_matched is always 0. */ + if (compose_status.chars_matched > 0 && nbytes == 0) + break; + orig_keysym = keysym; - if (numchars > 1) - { - Lisp_Object c; + /* Common for all keysym input events. */ + XSETFRAME (inev.frame_or_window, f); + inev.modifiers + = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), modifiers); + inev.timestamp = event.xkey.time; - /* First deal with keysyms which have defined - translations to characters. */ - if (keysym >= 32 && keysym < 128) - /* Avoid explicitly decoding each ASCII character. */ - { - bufp->kind = ASCII_KEYSTROKE_EVENT; - bufp->code = keysym; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp->modifiers - = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), - modifiers); - bufp->timestamp = event.xkey.time; - bufp++; - count++; - numchars--; - } - /* Now non-ASCII. */ - else if (HASH_TABLE_P (Vx_keysym_table) - && (NATNUMP (c = Fgethash (make_number (keysym), - Vx_keysym_table, - Qnil)))) - { - bufp->kind = (SINGLE_BYTE_CHAR_P (XFASTINT (c)) - ? ASCII_KEYSTROKE_EVENT - : MULTIBYTE_CHAR_KEYSTROKE_EVENT); - bufp->code = XFASTINT (c); - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp->modifiers - = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), - modifiers); - bufp->timestamp = event.xkey.time; - bufp++; - count++; - numchars--; - } - /* Random non-modifier sorts of keysyms. */ - else if (((keysym >= XK_BackSpace && keysym <= XK_Escape) + /* First deal with keysyms which have defined + translations to characters. */ + if (keysym >= 32 && keysym < 128) + /* Avoid explicitly decoding each ASCII character. */ + { + inev.kind = ASCII_KEYSTROKE_EVENT; + inev.code = keysym; + goto done_keysym; + } + + /* Now non-ASCII. */ + if (HASH_TABLE_P (Vx_keysym_table) + && (NATNUMP (c = Fgethash (make_number (keysym), + Vx_keysym_table, + Qnil)))) + { + inev.kind = (SINGLE_BYTE_CHAR_P (XFASTINT (c)) + ? ASCII_KEYSTROKE_EVENT + : MULTIBYTE_CHAR_KEYSTROKE_EVENT); + inev.code = XFASTINT (c); + goto done_keysym; + } + + /* Random non-modifier sorts of keysyms. */ + if (((keysym >= XK_BackSpace && keysym <= XK_Escape) || keysym == XK_Delete #ifdef XK_ISO_Left_Tab || (keysym >= XK_ISO_Left_Tab @@ -6413,104 +6447,81 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) <= XK_ISO_Last_Group_Lock) #endif )) - { - if (temp_index == sizeof temp_buffer / sizeof (short)) - temp_index = 0; - temp_buffer[temp_index++] = keysym; - /* make_lispy_event will convert this to a symbolic - key. */ - bufp->kind = NON_ASCII_KEYSTROKE_EVENT; - bufp->code = keysym; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp->modifiers - = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), - modifiers); - bufp->timestamp = event.xkey.time; - bufp++; - count++; - numchars--; - } - else if (numchars > nbytes) - { /* Raw bytes, not keysym. */ - register int i; - register int c; - int nchars, len; - - /* The input should be decoded with `coding_system' - which depends on which X*LookupString function - we used just above and the locale. */ - setup_coding_system (coding_system, &coding); - coding.src_multibyte = 0; - coding.dst_multibyte = 1; - /* The input is converted to events, thus we can't - handle composition. Anyway, there's no XIM that - gives us composition information. */ - coding.common_flags &= ~CODING_ANNOTATION_MASK; - - for (i = 0; i < nbytes; i++) - { - if (temp_index == (sizeof temp_buffer - / sizeof (short))) - temp_index = 0; - temp_buffer[temp_index++] = copy_bufptr[i]; - } + { + STORE_KEYSYM_FOR_DEBUG (keysym); + /* make_lispy_event will convert this to a symbolic + key. */ + inev.kind = NON_ASCII_KEYSTROKE_EVENT; + inev.code = keysym; + goto done_keysym; + } - { - /* Decode the input data. */ - coding.destination = (unsigned char *) malloc (nbytes); - if (! coding.destination) - break; - coding.dst_bytes = nbytes; - coding.mode |= CODING_MODE_LAST_BLOCK; - decode_coding_c_string (&coding, copy_bufptr, - nbytes, Qnil); - nbytes = coding.produced; - nchars = coding.produced_char; - if (copy_bufsiz < nbytes) - { - copy_bufsiz = nbytes; - copy_bufptr = (char *) alloca (nbytes); - } - bcopy (coding.destination, copy_bufptr, nbytes); - free (coding.destination); - } + { /* Raw bytes, not keysym. */ + register int i; + register int c; + int nchars, len; - /* Convert the input data to a sequence of - character events. */ - for (i = 0; i < nbytes; i += len) - { - if (nchars == nbytes) - c = copy_bufptr[i], len = 1; - else - c = STRING_CHAR_AND_LENGTH (copy_bufptr + i, - nbytes - i, len); - - bufp->kind = (ASCII_CHAR_P (c) - ? ASCII_KEYSTROKE_EVENT - : MULTIBYTE_CHAR_KEYSTROKE_EVENT); - bufp->code = c; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp->modifiers - = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), - modifiers); - bufp->timestamp = event.xkey.time; - bufp++; - } + for (i = 0, nchars = 0; i < nbytes; i++) + { + if (ASCII_BYTE_P (copy_bufptr[i])) + nchars++; + STORE_KEYSYM_FOR_DEBUG (copy_bufptr[i]); + } - count += nchars; - numchars -= nchars; + if (nchars < nbytes) + { + /* Decode the input data. */ + int require; + unsigned char *p; + + /* The input should be decoded with `coding_system' + which depends on which X*LookupString function + we used just above and the locale. */ + setup_coding_system (coding_system, &coding); + coding.src_multibyte = 0; + coding.dst_multibyte = 1; + /* The input is converted to events, thus we can't + handle composition. Anyway, there's no XIM that + gives us composition information. */ + coding.common_flags &= ~CODING_ANNOTATION_MASK; + + require = MAX_MULTIBYTE_LENGTH * nbytes; + coding.destination = alloca (require); + coding.dst_bytes = require; + coding.mode |= CODING_MODE_LAST_BLOCK; + decode_coding_c_string (&coding, copy_bufptr, nbytes, Qnil); + nbytes = coding.produced; + nchars = coding.produced_char; + copy_bufptr = coding.destination; + } - if (keysym == NoSymbol) - break; - } - else - abort (); - } - else - abort (); + /* Convert the input data to a sequence of + character events. */ + for (i = 0; i < nbytes; i += len) + { + if (nchars == nbytes) + c = copy_bufptr[i], len = 1; + else + c = STRING_CHAR_AND_LENGTH (copy_bufptr + i, + nbytes - i, len); + inev.kind = (SINGLE_BYTE_CHAR_P (c) + ? ASCII_KEYSTROKE_EVENT + : MULTIBYTE_CHAR_KEYSTROKE_EVENT); + inev.code = c; + kbd_buffer_store_event_hold (&inev, hold_quit); + } + + /* Previous code updated count by nchars rather than nbytes, + but that seems bogus to me. ++kfs */ + count += nbytes; + + inev.kind = NO_EVENT; /* Already stored above. */ + + if (keysym == NoSymbol) + break; + } } + done_keysym: #ifdef HAVE_X_I18N /* Don't dispatch this event since XtDispatchEvent calls XFilterEvent, and two calls in a row may freeze the @@ -6531,63 +6542,41 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) #endif case EnterNotify: - { - int n; + x_detect_focus_change (dpyinfo, &event, &inev); - n = x_detect_focus_change (dpyinfo, &event, bufp, numchars); - if (n > 0) - { - bufp += n, count += n, numchars -= n; - } + f = x_any_window_to_frame (dpyinfo, event.xcrossing.window); - f = x_any_window_to_frame (dpyinfo, event.xcrossing.window); + if (f && x_mouse_click_focus_ignore_position) + ignore_next_mouse_click_timeout = event.xmotion.time + 200; #if 0 - if (event.xcrossing.focus) - { - /* Avoid nasty pop/raise loops. */ - if (f && (!(f->auto_raise) - || !(f->auto_lower) - || (event.xcrossing.time - enter_timestamp) > 500)) - { - x_new_focus_frame (dpyinfo, f); - enter_timestamp = event.xcrossing.time; - } - } - else if (f == dpyinfo->x_focus_frame) - x_new_focus_frame (dpyinfo, 0); + if (event.xcrossing.focus) + { + /* Avoid nasty pop/raise loops. */ + if (f && (!(f->auto_raise) + || !(f->auto_lower) + || (event.xcrossing.time - enter_timestamp) > 500)) + { + x_new_focus_frame (dpyinfo, f); + enter_timestamp = event.xcrossing.time; + } + } + else if (f == dpyinfo->x_focus_frame) + x_new_focus_frame (dpyinfo, 0); #endif - /* EnterNotify counts as mouse movement, - so update things that depend on mouse position. */ - if (f && !f->output_data.x->hourglass_p) - note_mouse_movement (f, &event.xmotion); - goto OTHER; - } + /* EnterNotify counts as mouse movement, + so update things that depend on mouse position. */ + if (f && !f->output_data.x->hourglass_p) + note_mouse_movement (f, &event.xmotion); + goto OTHER; case FocusIn: - { - int n; - - n = x_detect_focus_change (dpyinfo, &event, bufp, numchars); - if (n > 0) - { - bufp += n, count += n, numchars -= n; - } - } - + x_detect_focus_change (dpyinfo, &event, &inev); goto OTHER; case LeaveNotify: - { - int n; - - n = x_detect_focus_change (dpyinfo, &event, bufp, numchars); - if (n > 0) - { - bufp += n, count += n, numchars -= n; - } - } + x_detect_focus_change (dpyinfo, &event, &inev); f = x_top_window_to_frame (dpyinfo, event.xcrossing.window); if (f) @@ -6605,31 +6594,12 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) Otherwise, the startup message is cleared when the mouse leaves the frame. */ if (any_help_event_p) - { - Lisp_Object frame; - int n; - - XSETFRAME (frame, f); - help_echo_string = Qnil; - n = gen_help_event (bufp, numchars, - Qnil, frame, Qnil, Qnil, 0); - bufp += n, count += n, numchars -= n; - } - + do_help = -1; } goto OTHER; case FocusOut: - { - int n; - - n = x_detect_focus_change (dpyinfo, &event, bufp, numchars); - if (n > 0) - { - bufp += n, count += n, numchars -= n; - } - } - + x_detect_focus_change (dpyinfo, &event, &inev); goto OTHER; case MotionNotify: @@ -6665,15 +6635,12 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) /* Window will be selected only when it is not selected now and last mouse movement event was not in it. Minibuffer window will be selected iff it is active. */ - if (WINDOWP(window) + if (WINDOWP (window) && !EQ (window, last_window) - && !EQ (window, selected_window) - && numchars > 0) + && !EQ (window, selected_window)) { - bufp->kind = SELECT_WINDOW_EVENT; - bufp->frame_or_window = window; - bufp->arg = Qnil; - ++bufp, ++count, --numchars; + inev.kind = SELECT_WINDOW_EVENT; + inev.frame_or_window = window; } last_window=window; @@ -6684,7 +6651,8 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) { #ifndef USE_TOOLKIT_SCROLL_BARS struct scroll_bar *bar - = x_window_to_scroll_bar (event.xmotion.window); + = x_window_to_scroll_bar (event.xmotion.display, + event.xmotion.window); if (bar) x_scroll_bar_note_movement (bar, &event); @@ -6699,22 +6667,7 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) has changed, generate a HELP_EVENT. */ if (!NILP (help_echo_string) || !NILP (previous_help_echo_string)) - { - Lisp_Object frame; - int n; - - if (f) - XSETFRAME (frame, f); - else - frame = Qnil; - - any_help_event_p = 1; - n = gen_help_event (bufp, numchars, help_echo_string, frame, - help_echo_window, help_echo_object, - help_echo_pos); - bufp += n, count += n, numchars -= n; - } - + do_help = 1; goto OTHER; } @@ -6773,7 +6726,7 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) Convert that to the position of the window manager window. */ x_real_positions (f, &f->left_pos, &f->top_pos); - x_check_fullscreen_move (f); + x_check_expected_move (f); if (f->want_fullscreen & FULLSCREEN_WAIT) f->want_fullscreen &= ~(FULLSCREEN_WAIT|FULLSCREEN_BOTH); } @@ -6798,10 +6751,8 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) { /* If we decide we want to generate an event to be seen by the rest of Emacs, we put it here. */ - struct input_event emacs_event; int tool_bar_p = 0; - emacs_event.kind = NO_EVENT; bzero (&compose_status, sizeof (compose_status)); if (dpyinfo->grabbed @@ -6841,25 +6792,40 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) #if defined (USE_X_TOOLKIT) || defined (USE_GTK) if (! popup_activated ()) #endif - construct_mouse_click (&emacs_event, &event, f); + { + if (ignore_next_mouse_click_timeout) + { + if (event.type == ButtonPress + && (int)(event.xbutton.time - ignore_next_mouse_click_timeout) > 0) + { + ignore_next_mouse_click_timeout = 0; + construct_mouse_click (&inev, &event, f); + } + if (event.type == ButtonRelease) + ignore_next_mouse_click_timeout = 0; + } + else + construct_mouse_click (&inev, &event, f); + } } } else { struct scroll_bar *bar - = x_window_to_scroll_bar (event.xbutton.window); + = x_window_to_scroll_bar (event.xbutton.display, + event.xbutton.window); #ifdef USE_TOOLKIT_SCROLL_BARS /* Make the "Ctrl-Mouse-2 splits window" work for toolkit scroll bars. */ if (bar && event.xbutton.state & ControlMask) { - x_scroll_bar_handle_click (bar, &event, &emacs_event); + x_scroll_bar_handle_click (bar, &event, &inev); *finish = X_EVENT_DROP; } #else /* not USE_TOOLKIT_SCROLL_BARS */ if (bar) - x_scroll_bar_handle_click (bar, &event, &emacs_event); + x_scroll_bar_handle_click (bar, &event, &inev); #endif /* not USE_TOOLKIT_SCROLL_BARS */ } @@ -6880,14 +6846,6 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) else dpyinfo->grabbed &= ~(1 << event.xbutton.button); - if (numchars >= 1 && emacs_event.kind != NO_EVENT) - { - bcopy (&emacs_event, bufp, sizeof (struct input_event)); - bufp++; - count++; - numchars--; - } - #if defined (USE_X_TOOLKIT) || defined (USE_GTK) f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window); /* For a down-event in the menu bar, @@ -6974,16 +6932,38 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) break; } - goto ret; + done: + if (inev.kind != NO_EVENT) + { + kbd_buffer_store_event_hold (&inev, hold_quit); + count++; + } - out: - *finish = X_EVENT_GOTO_OUT; + if (do_help + && !(hold_quit && hold_quit->kind != NO_EVENT)) + { + Lisp_Object frame; - ret: - *bufp_r = bufp; - *numcharsp = numchars; - *eventp = event; + if (f) + XSETFRAME (frame, f); + else + frame = Qnil; + if (do_help > 0) + { + any_help_event_p = 1; + gen_help_event (help_echo_string, frame, help_echo_window, + help_echo_object, help_echo_pos); + } + else + { + help_echo_string = Qnil; + gen_help_event (Qnil, frame, Qnil, Qnil, 0); + } + count++; + } + + *eventp = event; return count; } @@ -6999,30 +6979,12 @@ x_dispatch_event (event, display) Display *display; { struct x_display_info *dpyinfo; - struct input_event bufp[10]; - struct input_event *bufpp; - int numchars = 10; int finish = X_EVENT_NORMAL; - for (bufpp = bufp; bufpp != bufp + 10; bufpp++) - EVENT_INIT (*bufpp); - bufpp = bufp; - - for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) - if (dpyinfo->display == display) - break; + dpyinfo = x_display_info_for_display (display); if (dpyinfo) - { - int i, events; - events = handle_one_xevent (dpyinfo, - event, - &bufpp, - &numchars, - &finish); - for (i = 0; i < events; ++i) - kbd_buffer_store_event (&bufp[i]); - } + handle_one_xevent (dpyinfo, event, &finish, 0); return finish; } @@ -7032,19 +6994,16 @@ x_dispatch_event (event, display) This routine is called by the SIGIO handler. We return as soon as there are no more events to be read. - Events representing keys are stored in buffer BUFP, - which can hold up to NUMCHARS characters. We return the number of characters stored into the buffer, thus pretending to be `read'. EXPECTED is nonzero if the caller knows input is available. */ static int -XTread_socket (sd, bufp, numchars, expected) +XTread_socket (sd, expected, hold_quit) register int sd; - /* register */ struct input_event *bufp; - /* register */ int numchars; int expected; + struct input_event *hold_quit; { int count = 0; XEvent event; @@ -7063,9 +7022,6 @@ XTread_socket (sd, bufp, numchars, expected) /* So people can tell when we have read the available input. */ input_signal_count++; - if (numchars <= 0) - abort (); /* Don't think this happens. */ - ++handling_signal; /* Find the display we are supposed to read input for. @@ -7107,35 +7063,21 @@ XTread_socket (sd, bufp, numchars, expected) } #ifdef HAVE_X_SM - BLOCK_INPUT; - count += x_session_check_input (bufp, &numchars); - UNBLOCK_INPUT; + { + struct input_event inev; + BLOCK_INPUT; + /* We don't need to EVENT_INIT (inev) here, as + x_session_check_input copies an entire input_event. */ + if (x_session_check_input (&inev)) + { + kbd_buffer_store_event_hold (&inev, hold_quit); + count++; + } + UNBLOCK_INPUT; + } #endif -#ifdef USE_GTK - /* For GTK we must use the GTK event loop. But XEvents gets passed - to our filter function above, and then to the big event switch. - We use a bunch of globals to communicate with our filter function, - that is kind of ugly, but it works. */ - current_dpyinfo = dpyinfo; - - while (gtk_events_pending ()) - { - current_count = count; - current_numcharsp = &numchars; - current_bufp = &bufp; - - gtk_main_iteration (); - - count = current_count; - current_bufp = 0; - current_numcharsp = 0; - - if (current_finish == X_EVENT_GOTO_OUT) - goto out; - } - -#else /* not USE_GTK */ +#ifndef USE_GTK while (XPending (dpyinfo->display)) { int finish; @@ -7149,17 +7091,39 @@ XTread_socket (sd, bufp, numchars, expected) #endif event_found = 1; - count += handle_one_xevent (dpyinfo, - &event, - &bufp, - &numchars, - &finish); + count += handle_one_xevent (dpyinfo, &event, &finish, hold_quit); if (finish == X_EVENT_GOTO_OUT) goto out; } -#endif /* USE_GTK */ +#endif /* not USE_GTK */ + } + +#ifdef USE_GTK + + /* For GTK we must use the GTK event loop. But XEvents gets passed + to our filter function above, and then to the big event switch. + We use a bunch of globals to communicate with our filter function, + that is kind of ugly, but it works. + + There is no way to do one display at the time, GTK just does events + from all displays. */ + + while (gtk_events_pending ()) + { + current_count = count; + current_hold_quit = hold_quit; + + gtk_main_iteration (); + + count = current_count; + current_count = -1; + current_hold_quit = 0; + + if (current_finish == X_EVENT_GOTO_OUT) + break; } +#endif /* USE_GTK */ out:; @@ -7194,8 +7158,9 @@ XTread_socket (sd, bufp, numchars, expected) pending_autoraise_frame = 0; } - UNBLOCK_INPUT; --handling_signal; + UNBLOCK_INPUT; + return count; } @@ -7250,13 +7215,6 @@ x_draw_hollow_cursor (w, row) struct glyph *cursor_glyph; GC gc; - /* Compute frame-relative coordinates from window-relative - coordinates. */ - x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); - y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y) - + row->ascent - w->phys_cursor_ascent); - h = row->height - 1; - /* Get the glyph the cursor is on. If we can't tell because the current matrix is invalid or such, give up. */ cursor_glyph = get_phys_cursor_glyph (w); @@ -7273,6 +7231,19 @@ x_draw_hollow_cursor (w, row) wd = min (FRAME_COLUMN_WIDTH (f), wd); w->phys_cursor_width = wd; + /* Compute frame-relative coordinates from window-relative + coordinates. */ + x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); + y = WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y); + + /* Compute the proper height and ascent of the rectangle, based + on the actual glyph. Using the full height of the row looks + bad when there are tall images on that row. */ + h = max (FRAME_LINE_HEIGHT (f), cursor_glyph->ascent + cursor_glyph->descent); + if (h < row->height) + y += row->ascent /* - w->phys_cursor_ascent */ + cursor_glyph->descent - h; + h--; + /* The foreground of cursor_gc is typically the same as the normal background color, which can cause the cursor box to be invisible. */ xgcv.foreground = f->output_data.x->cursor_pixel; @@ -7416,6 +7387,13 @@ x_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, activ w->phys_cursor_type = cursor_type; w->phys_cursor_on_p = 1; + if (glyph_row->exact_window_width_line_p + && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA]) + { + glyph_row->cursor_in_fringe_p = 1; + draw_fringe_bitmap (w, glyph_row, 0); + } + else switch (cursor_type) { case HOLLOW_BOX_CURSOR: @@ -7478,13 +7456,13 @@ x_bitmap_icon (f, file) if (STRINGP (file)) { #ifdef USE_GTK - /* Use gtk_window_set_icon_from_file() if available, + /* Use gtk_window_set_icon_from_file () if available, It's not restricted to bitmaps */ - if (xg_set_icon(f, file)) + if (xg_set_icon (f, file)) return 0; #endif /* USE_GTK */ bitmap_id = x_create_bitmap_from_file (f, file); - x_create_bitmap_mask(f, bitmap_id); + x_create_bitmap_mask (f, bitmap_id); } else { @@ -7494,7 +7472,7 @@ x_bitmap_icon (f, file) FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id = x_create_bitmap_from_data (f, gnu_bits, gnu_width, gnu_height); - x_create_bitmap_mask(f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id); + x_create_bitmap_mask (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id); } /* The first time we create the GNU bitmap and mask, @@ -7763,6 +7741,11 @@ x_connection_closed (dpy, error_message) } #endif +#ifdef USE_GTK + if (dpyinfo) + xg_display_close (dpyinfo->display); +#endif + /* Indicate that this display is dead. */ if (dpyinfo) dpyinfo->display = 0; @@ -8216,65 +8199,24 @@ x_calc_absolute_position (f) Window child; int win_x = 0, win_y = 0; int flags = f->size_hint_flags; - int this_window; /* We have nothing to do if the current position is already for the top-left corner. */ if (! ((flags & XNegative) || (flags & YNegative))) return; - this_window = FRAME_OUTER_WINDOW (f); - - /* Find the position of the outside upper-left corner of + /* Find the offsets of the outside upper-left corner of the inner window, with respect to the outer window. But do this only if we will need the results. */ if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window) - { - int count; - - BLOCK_INPUT; - count = x_catch_errors (FRAME_X_DISPLAY (f)); - while (1) - { - x_clear_errors (FRAME_X_DISPLAY (f)); - XTranslateCoordinates (FRAME_X_DISPLAY (f), - - /* From-window, to-window. */ - this_window, - f->output_data.x->parent_desc, - - /* From-position, to-position. */ - 0, 0, &win_x, &win_y, - - /* Child of win. */ - &child); - if (x_had_errors_p (FRAME_X_DISPLAY (f))) - { - Window newroot, newparent = 0xdeadbeef; - Window *newchildren; - unsigned int nchildren; - - if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot, - &newparent, &newchildren, &nchildren)) - break; - - XFree ((char *) newchildren); - - f->output_data.x->parent_desc = newparent; - } - else - break; - } - - x_uncatch_errors (FRAME_X_DISPLAY (f), count); - UNBLOCK_INPUT; - } + /* This is to get *_pixels_outer_diff. */ + x_real_positions (f, &win_x, &win_y); /* Treat negative positions as relative to the leftmost bottommost position that fits on the screen. */ if (flags & XNegative) f->left_pos = (FRAME_X_DISPLAY_INFO (f)->width - - 2 * f->border_width - win_x + - 2 * FRAME_X_OUTPUT (f)->x_pixels_outer_diff - FRAME_PIXEL_WIDTH (f) + f->left_pos); @@ -8299,8 +8241,12 @@ x_calc_absolute_position (f) if (flags & YNegative) f->top_pos = (FRAME_X_DISPLAY_INFO (f)->height - - 2 * f->border_width - - win_y + - FRAME_X_OUTPUT (f)->y_pixels_outer_diff + + /* Assume the window manager decorations are the same size on + three sides, i.e. left, right and bottom. This is to + compensate for the bottom part. */ + - FRAME_X_OUTPUT (f)->x_pixels_outer_diff - height + f->top_pos); } @@ -8343,19 +8289,27 @@ x_set_offset (f, xoff, yoff, change_gravity) modified_left = f->left_pos; modified_top = f->top_pos; -#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal, - this seems to be unnecessary and incorrect. rms, 4/17/97. */ - /* It is a mystery why we need to add the border_width here - when the frame is already visible, but experiment says we do. */ - if (change_gravity != 0) + + if (FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A) { - modified_left += f->border_width; - modified_top += f->border_width; + /* Some WMs (twm, wmaker at least) has an offset that is smaller + than the WM decorations. So we use the calculated offset instead + of the WM decoration sizes here (x/y_pixels_outer_diff). */ + modified_left += FRAME_X_OUTPUT (f)->move_offset_left; + modified_top += FRAME_X_OUTPUT (f)->move_offset_top; } -#endif XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), modified_left, modified_top); + + if (FRAME_VISIBLE_P (f) + && FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN) + { + FRAME_X_OUTPUT (f)->check_expected_move = 1; + FRAME_X_OUTPUT (f)->expected_top = f->top_pos; + FRAME_X_OUTPUT (f)->expected_left = f->left_pos; + } + UNBLOCK_INPUT; } @@ -8376,7 +8330,7 @@ x_check_fullscreen (f) /* We do not need to move the window, it shall be taken care of when setting WM manager hints. If the frame is visible already, the position is checked by - x_check_fullscreen_move. */ + x_check_expected_move. */ if (FRAME_COLS (f) != width || FRAME_LINES (f) != height) { change_frame_size (f, height, width, 0, 1, 0); @@ -8390,30 +8344,33 @@ x_check_fullscreen (f) } /* If frame parameters are set after the frame is mapped, we need to move - the window. This is done in xfns.c. + the window. Some window managers moves the window to the right position, some moves the outer window manager window to the specified position. Here we check that we are in the right spot. If not, make a second move, assuming we are dealing with the second kind of window manager. */ static void -x_check_fullscreen_move (f) +x_check_expected_move (f) struct frame *f; { - if (f->want_fullscreen & FULLSCREEN_MOVE_WAIT) + if (FRAME_X_OUTPUT (f)->check_expected_move) { - int expect_top = f->top_pos; - int expect_left = f->left_pos; - - if (f->want_fullscreen & FULLSCREEN_HEIGHT) - expect_top = 0; - if (f->want_fullscreen & FULLSCREEN_WIDTH) - expect_left = 0; + int expect_top = FRAME_X_OUTPUT (f)->expected_top; + int expect_left = FRAME_X_OUTPUT (f)->expected_left; if (expect_top != f->top_pos || expect_left != f->left_pos) - x_set_offset (f, expect_left, expect_top, 1); + { + FRAME_X_DISPLAY_INFO (f)->wm_type = X_WMTYPE_A; + FRAME_X_OUTPUT (f)->move_offset_left = expect_left - f->left_pos; + FRAME_X_OUTPUT (f)->move_offset_top = expect_top - f->top_pos; + + x_set_offset (f, expect_left, expect_top, 1); + } + else if (FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN) + FRAME_X_DISPLAY_INFO (f)->wm_type = X_WMTYPE_B; /* Just do this once */ - f->want_fullscreen &= ~FULLSCREEN_MOVE_WAIT; + FRAME_X_OUTPUT (f)->check_expected_move = 0; } } @@ -9576,9 +9533,8 @@ x_list_fonts (f, pattern, size, maxnames) int average_width = -1, resx = 0, dashes = 0; /* Count the number of dashes in NAMES[I]. If there are - 14 dashes, the field value following 7th dash - (PIXEL_SIZE) is zero, the field value following 9th - dash (RESOLUTION_X) is nonzero, and the field value + 14 dashes, the field value following 9th dash + (RESOLUTION_X) is nonzero, and the field value following 12th dash (AVERAGE_WIDTH) is 0, this is a auto-scaled font which is usually too ugly to be used for editing. Let's ignore it. */ @@ -9595,8 +9551,7 @@ x_list_fonts (f, pattern, size, maxnames) } if (allow_auto_scaled_font - || dashes < 14 - || ! (width == 0 && resx != 0 && average_width == 0)) + || dashes < 14 || average_width != 0 || resx == 0) { tem = build_string (names[i]); if (NILP (Fassoc (tem, list))) @@ -9894,6 +9849,7 @@ x_load_font (f, fontname, size) /* Now fill in the slots of *FONTP. */ BLOCK_INPUT; + bzero (fontp, sizeof (*fontp)); fontp->font = font; fontp->font_idx = i; fontp->charset = -1; /* fs_load_font sets it. */ @@ -10303,6 +10259,34 @@ same_x_server (name1, name2) } #endif +/* Count number of set bits in mask and number of bits to shift to + get to the first bit. With MASK 0x7e0, *BITS is set to 6, and *OFFSET + to 5. */ +static void +get_bits_and_offset (mask, bits, offset) + unsigned long mask; + int *bits; + int *offset; +{ + int nr = 0; + int off = 0; + + while (!(mask & 1)) + { + off++; + mask >>= 1; + } + + while (mask & 1) + { + nr++; + mask >>= 1; + } + + *offset = off; + *bits = nr; +} + struct x_display_info * x_term_init (display_name, xrm_option, resource_name) Lisp_Object display_name; @@ -10319,7 +10303,7 @@ x_term_init (display_name, xrm_option, resource_name) if (!x_initialized) { x_initialize (); - x_initialized = 1; + ++x_initialized; } #ifdef USE_GTK @@ -10330,61 +10314,65 @@ x_term_init (display_name, xrm_option, resource_name) char **argv2 = argv; GdkAtom atom; - /* GTK 2.0 can only handle one display, GTK 2.2 can handle more - than one, but this remains to be implemented. */ - if (x_initialized > 1) - return 0; - - x_initialized++; - - for (argc = 0; argc < NUM_ARGV; ++argc) - argv[argc] = 0; + if (x_initialized++ > 1) + { + /* Opening another display. If xg_display_open returns less + than zero, we are probably on GTK 2.0, which can only handle + one display. GTK 2.2 or later can handle more than one. */ + if (xg_display_open (SDATA (display_name), &dpy) < 0) + error ("Sorry, this version of GTK can only handle one display"); + } + else + { + for (argc = 0; argc < NUM_ARGV; ++argc) + argv[argc] = 0; - argc = 0; - argv[argc++] = initial_argv[0]; + argc = 0; + argv[argc++] = initial_argv[0]; - if (! NILP (display_name)) - { - argv[argc++] = "--display"; - argv[argc++] = SDATA (display_name); - } + if (! NILP (display_name)) + { + argv[argc++] = "--display"; + argv[argc++] = SDATA (display_name); + } - argv[argc++] = "--name"; - argv[argc++] = resource_name; + argv[argc++] = "--name"; + argv[argc++] = resource_name; #ifdef HAVE_X11R5 - XSetLocaleModifiers (""); + XSetLocaleModifiers (""); #endif - gtk_init (&argc, &argv2); + gtk_init (&argc, &argv2); - /* gtk_init does set_locale. We must fix locale after calling it. */ - fixup_locale (); - xg_initialize (); + /* gtk_init does set_locale. We must fix locale after calling it. */ + fixup_locale (); + xg_initialize (); - dpy = GDK_DISPLAY (); + dpy = GDK_DISPLAY (); - /* NULL window -> events for all windows go to our function */ - gdk_window_add_filter (NULL, event_handler_gdk, NULL); + /* NULL window -> events for all windows go to our function */ + gdk_window_add_filter (NULL, event_handler_gdk, NULL); - /* Load our own gtkrc if it exists. */ - { - struct gcpro gcpro1, gcpro2; - char *file = "~/.emacs.d/gtkrc"; - Lisp_Object s, abs_file; + /* Load our own gtkrc if it exists. */ + { + struct gcpro gcpro1, gcpro2; + char *file = "~/.emacs.d/gtkrc"; + Lisp_Object s, abs_file; - GCPRO2 (s, abs_file); - s = make_string (file, strlen (file)); - abs_file = Fexpand_file_name(s, Qnil); + GCPRO2 (s, abs_file); + s = make_string (file, strlen (file)); + abs_file = Fexpand_file_name (s, Qnil); - if (! NILP (abs_file) && !NILP (Ffile_readable_p (abs_file))) - gtk_rc_parse (SDATA (abs_file)); + if (! NILP (abs_file) && !NILP (Ffile_readable_p (abs_file))) + gtk_rc_parse (SDATA (abs_file)); - UNGCPRO; - } + UNGCPRO; + } - XSetErrorHandler (x_error_handler); - XSetIOErrorHandler (x_io_error_quitter); + XSetErrorHandler (x_error_handler); + XSetIOErrorHandler (x_io_error_quitter); + } } #else /* not USE_GTK */ #ifdef USE_X_TOOLKIT @@ -10505,6 +10493,11 @@ x_term_init (display_name, xrm_option, resource_name) x_find_modifier_meanings (dpyinfo); /* Get the scroll bar cursor. */ +#ifdef USE_GTK + /* We must create a GTK cursor, it is required for GTK widgets. */ + dpyinfo->xg_cursor = xg_create_default_cursor (dpyinfo->display); +#endif /* USE_GTK */ + dpyinfo->vertical_scroll_bar_cursor = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow); @@ -10526,6 +10519,7 @@ x_term_init (display_name, xrm_option, resource_name) dpyinfo->height = HeightOfScreen (dpyinfo->screen); dpyinfo->width = WidthOfScreen (dpyinfo->screen); dpyinfo->root_window = RootWindowOfScreen (dpyinfo->screen); + dpyinfo->client_leader_window = 0; dpyinfo->grabbed = 0; dpyinfo->reference_count = 0; dpyinfo->icon_bitmap_id = -1; @@ -10550,6 +10544,21 @@ x_term_init (display_name, xrm_option, resource_name) dpyinfo->x_focus_event_frame = 0; dpyinfo->x_highlight_frame = 0; dpyinfo->image_cache = make_image_cache (); + dpyinfo->wm_type = X_WMTYPE_UNKNOWN; + + /* See if we can construct pixel values from RGB values. */ + dpyinfo->red_bits = dpyinfo->blue_bits = dpyinfo->green_bits = 0; + dpyinfo->red_offset = dpyinfo->blue_offset = dpyinfo->green_offset = 0; + + if (dpyinfo->visual->class == TrueColor) + { + get_bits_and_offset (dpyinfo->visual->red_mask, + &dpyinfo->red_bits, &dpyinfo->red_offset); + get_bits_and_offset (dpyinfo->visual->blue_mask, + &dpyinfo->blue_bits, &dpyinfo->blue_offset); + get_bits_and_offset (dpyinfo->visual->green_mask, + &dpyinfo->green_bits, &dpyinfo->green_offset); + } /* See if a private colormap is requested. */ if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen)) @@ -10595,6 +10604,8 @@ x_term_init (display_name, xrm_option, resource_name) = XInternAtom (dpyinfo->display, "WM_CONFIGURE_DENIED", False); dpyinfo->Xatom_wm_window_moved = XInternAtom (dpyinfo->display, "WM_MOVED", False); + dpyinfo->Xatom_wm_client_leader + = XInternAtom (dpyinfo->display, "WM_CLIENT_LEADER", False); dpyinfo->Xatom_editres = XInternAtom (dpyinfo->display, "Editres", False); dpyinfo->Xatom_CLIPBOARD @@ -10749,6 +10760,12 @@ x_term_init (display_name, xrm_option, resource_name) #endif } +#ifdef HAVE_X_SM + /* Only do this for the first display. */ + if (x_initialized == 1) + x_session_initialize (dpyinfo); +#endif + UNBLOCK_INPUT; return dpyinfo; @@ -10761,6 +10778,8 @@ void x_delete_display (dpyinfo) struct x_display_info *dpyinfo; { + int i; + delete_keyboard_wait_descriptor (dpyinfo->connection); /* Discard this display from x_display_name_list and x_display_list. @@ -10812,6 +10831,18 @@ x_delete_display (dpyinfo) xim_close_dpy (dpyinfo); #endif + /* Free the font names in the font table. */ + for (i = 0; i < dpyinfo->n_fonts; i++) + if (dpyinfo->font_table[i].name) + { + if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name) + xfree (dpyinfo->font_table[i].full_name); + xfree (dpyinfo->font_table[i].name); + } + + if (dpyinfo->font_table->font_encoder) + xfree (dpyinfo->font_table->font_encoder); + xfree (dpyinfo->font_table); xfree (dpyinfo->x_id_name); xfree (dpyinfo->color_cells); @@ -10867,6 +10898,8 @@ static struct redisplay_interface x_redisplay_interface = x_get_glyph_overhangs, x_fix_overlapping_area, x_draw_fringe_bitmap, + 0, /* define_fringe_bitmap */ + 0, /* destroy_fringe_bitmap */ x_per_char_metric, x_encode_char, x_compute_glyph_string_overhangs, @@ -10913,6 +10946,11 @@ x_initialize () x_noop_count = 0; last_tool_bar_item = -1; any_help_event_p = 0; + ignore_next_mouse_click_timeout = 0; + +#ifdef USE_GTK + current_count = -1; +#endif /* Try to use interrupt input; if we can't, then start polling. */ Fset_input_mode (Qt, Qnil, Qt, Qnil); @@ -10962,10 +11000,6 @@ x_initialize () #endif /* SIGWINCH */ signal (SIGPIPE, x_connection_signal); - -#ifdef HAVE_X_SM - x_session_initialize (); -#endif } @@ -10998,6 +11032,16 @@ UNDERLINE_POSITION font properties, for example 7x13 on XFree prior to 4.1, set this to nil. */); x_use_underline_position_properties = 1; + DEFVAR_BOOL ("x-mouse-click-focus-ignore-position", + &x_mouse_click_focus_ignore_position, + doc: /* Non-nil means that a mouse click to focus a frame does not move point. +This variable is only used when the window manager requires that you +click on a frame to select it (give it focus). In that case, a value +of nil, means that the selected window and cursor position changes to +reflect the mouse click position, while a non-nil value means that the +selected window or cursor position is preserved. */); + x_mouse_click_focus_ignore_position = 0; + DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars, doc: /* What X toolkit scroll bars Emacs uses. A value of nil means Emacs doesn't use X toolkit scroll bars. @@ -11066,3 +11110,6 @@ default is nil, which is the same as `super'. */); } #endif /* HAVE_X_WINDOWS */ + +/* arch-tag: 6d4e4cb7-abc1-4302-9585-d84dcfb09d0f + (do not change this comment) */ diff --git a/src/xterm.h b/src/xterm.h index 86cda277476..fe0449a3bc5 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -183,9 +183,17 @@ struct x_display_info /* The root window of this screen. */ Window root_window; + /* Client leader window. */ + Window client_leader_window; + /* The cursor to use for vertical scroll bars. */ Cursor vertical_scroll_bar_cursor; +#ifdef USE_GTK + /* The GDK cursor for scroll bars and popup menus. */ + GdkCursor *xg_cursor; +#endif + /* X Resource data base */ XrmDatabase xrdb; @@ -289,6 +297,7 @@ struct x_display_info /* Other WM communication */ Atom Xatom_wm_configure_denied; /* When our config request is denied */ Atom Xatom_wm_window_moved; /* When the WM moves us. */ + Atom Xatom_wm_client_leader; /* Id of client leader window. */ /* EditRes protocol */ Atom Xatom_editres; @@ -356,6 +365,23 @@ struct x_display_info use this directly, call x_color_cells instead. */ XColor *color_cells; int ncolor_cells; + + /* Bits and shifts to use to compose pixel values on TrueColor visuals. */ + int red_bits, blue_bits, green_bits; + int red_offset, blue_offset, green_offset; + + /* The type of window manager we have. If we move FRAME_OUTER_WINDOW + to x/y 0/0, some window managers (type A) puts the window manager + decorations outside the screen and FRAME_OUTER_WINDOW exactly at 0/0. + Other window managers (type B) puts the window including decorations + at 0/0, so FRAME_OUTER_WINDOW is a bit below 0/0. + Record the type of WM in use so we can compensate for type A WMs. */ + enum + { + X_WMTYPE_UNKNOWN, + X_WMTYPE_A, + X_WMTYPE_B + } wm_type; }; #ifdef HAVE_X_I18N @@ -605,6 +631,19 @@ struct x_output frame, or IMPLICIT if we received an EnterNotify. FocusOut and LeaveNotify clears EXPLICIT/IMPLICIT. */ int focus_state; + + /* The latest move we made to FRAME_OUTER_WINDOW. Saved so we can + compensate for type A WMs (see wm_type in dpyinfo above). */ + int expected_top; + int expected_left; + + /* The offset we need to add to compensate for type A WMs. */ + int move_offset_top; + int move_offset_left; + + /* Nonzero if we have made a move and needs to check if the WM placed us + at the right position. */ + int check_expected_move; }; #define No_Cursor (None) @@ -970,18 +1009,25 @@ extern void x_handle_selection_request P_ ((struct input_event *)); extern void x_handle_selection_clear P_ ((struct input_event *)); extern void x_clear_frame_selections P_ ((struct frame *)); +extern int x_handle_dnd_message P_ ((struct frame *, + XClientMessageEvent *, + struct x_display_info *, + struct input_event *bufp)); +extern int x_check_property_data P_ ((Lisp_Object)); +extern void x_fill_property_data P_ ((Display *, + Lisp_Object, + void *, + int)); +extern Lisp_Object x_property_data_to_lisp P_ ((struct frame *, + unsigned char *, + Atom, + int, + unsigned long)); + /* Defined in xfns.c */ +extern struct x_display_info * check_x_display_info P_ ((Lisp_Object frame)); extern int have_menus_p P_ ((void)); -extern int x_bitmap_height P_ ((struct frame *, int)); -extern int x_bitmap_width P_ ((struct frame *, int)); -extern int x_bitmap_pixmap P_ ((struct frame *, int)); -extern void x_reference_bitmap P_ ((struct frame *, int)); -extern int x_create_bitmap_from_data P_ ((struct frame *, char *, - unsigned int, unsigned int)); -extern int x_create_bitmap_from_file P_ ((struct frame *, Lisp_Object)); -extern void x_destroy_bitmap P_ ((struct frame *, int)); -extern int x_create_bitmap_mask P_ ((struct frame * , int)); #ifdef USE_GTK extern int xg_set_icon P_ ((struct frame *, Lisp_Object)); @@ -1023,6 +1069,7 @@ extern void x_free_dpy_colors P_ ((Display *, Screen *, Colormap, extern void x_activate_menubar P_ ((struct frame *)); extern int popup_activated P_ ((void)); extern void initialize_frame_menubar P_ ((struct frame *)); +extern void free_frame_menubar P_ ((struct frame *)); /* Defined in widget.c */ @@ -1032,9 +1079,8 @@ extern void widget_store_internal_border P_ ((Widget)); /* Defined in xsmfns.c */ #ifdef HAVE_X_SM -extern void x_session_initialize P_ ((void)); -extern int x_session_check_input P_ ((struct input_event *bufp, - int *numchars)); +extern void x_session_initialize P_ ((struct x_display_info *dpyinfo)); +extern int x_session_check_input P_ ((struct input_event *bufp)); extern int x_session_have_connection P_ ((void)); #endif @@ -1056,3 +1102,6 @@ extern int x_session_have_connection P_ ((void)); (nr).y = (ry), \ (nr).width = (rwidth), \ (nr).height = (rheight)) + +/* arch-tag: 78a7972a-b18f-4694-861a-0780c4b3090e + (do not change this comment) */ |